2019-06-12
Spring整合JDBC配置
Spring提供了對(duì)持久層的整合功能,包括對(duì)JDBC以及各種ORM映射工具(如Hibernate、MyBatis)的整合封裝。Spring對(duì)JDBC的封裝使用的是模板設(shè)計(jì)模式。原來直接使用JDBC所需要的重復(fù)性代碼都可以在模板類中完成,極大地簡(jiǎn)化JDBC的使用。
<!--引入property配置文件 -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--初始化數(shù)據(jù)源 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${user}" />
<property name="password" value="${password}" />
</bean>
<!--初始化操作模板 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg><ref bean="dataSource"/></constructor-arg>
</bean>
JdbcTemplate類
org.springframework.jdbc.core.JdbcTemplate類是Spring提供的JDBC操作模板類,該類是線程安全的(使用ThreadLocal機(jī)制保證數(shù)據(jù)庫連接或會(huì)話對(duì)象的線程安全),可以方便地執(zhí)行CRUD操作。
主要方法:
- queryForMap:將查詢結(jié)果封裝為Map<String,Object>對(duì)象返回
- queryForList:將查詢結(jié)果封裝為List<Map<String, Object>>返回
- queryForObject:將查詢結(jié)果封裝為對(duì)象返回。可以使用RowMapper映射器將查詢結(jié)果集映射到用戶自定義類中。映射器通過名稱匹配的方式,自動(dòng)將一行數(shù)據(jù)映射到指定類的實(shí)例中,并支持下劃線到駝峰的轉(zhuǎn)換
- query:將查詢結(jié)果封裝為List集合返回??梢允褂肦owMapper映射器將查詢結(jié)果集映射到用戶自定義類中
- update:執(zhí)行增、刪、改,返回更新行數(shù)
- batchUpdate(sql, List<Object[]>:可以批量插入記錄
//實(shí)例化JdbcTemplate類,傳入dataSource對(duì)象
JdbcTemplate template = new JdbcTemplate(dataSource);
/********************** 查詢單條數(shù)據(jù),返回Map *************************/
String sql = "SELECT * FROM DEPT WHERE DEPTNO = ?";
Map<String, Object> result = template.queryForMap(sql,10);
/*********************** 查詢多條數(shù)據(jù),返回List<Map>*********************/
String sql = "SELECT * FROM DEPT";
List<Map<String, Object>> lists = template.queryForList(sql);
/************************查詢單條數(shù)據(jù),返回實(shí)體對(duì)象************************/
String sql = "SELECT * FROM DEPT WHERE DEPTNO = ?";
//指定數(shù)據(jù)表所對(duì)應(yīng)的實(shí)體類
RowMapper<Dept> rowMapper = new BeanPropertyRowMapper<Dept>(Dept.class);
Dept dept = template.queryForObject(sql, rowMapper, 10);
if (dept != null) {
System.out.println(dept.getDeptno() + "\t" + dept.getDname()
+ "\t" + dept.getLoc());
}
/**************** 查詢多條數(shù)據(jù),返回List,泛型為實(shí)體對(duì)象 ************************/
String sql = "SELECT * FROM DEPT";
RowMapper<Dept> rowMapper = new BeanPropertyRowMapper<Dept>(Dept.class);
List<Dept> lists = template.query(sql, rowMapper);
if (lists != null) {
for (Dept item : lists)
System.out.println(item.getDeptno() + "\t" + item.getDname()
+ "\t" + item.getLoc());
}
/********************** 統(tǒng)計(jì)記錄數(shù)量 ************************/
String sql = "SELECT COUNT(*) as 人數(shù) FROM DEPT";
int result = template.queryForObject(sql, Integer.class);
System.out.println(result);
/************************ 增加操作 *****************************/
String sql = "INSERT INTO DEPT(DEPTNO, DNAME, LOC) VALUES( ?, ?, ? )";
int cnt = template.update(sql, new Object[] { 50, "中國分部", "中國" });
/************************ 刪除操作 ****************************/
String sql = "DELETE FROM DEPT WHERE DEPTNO = ?";
cnt = template.update(sql, new Object[] { 50 });
注意事項(xiàng):
- 使用BeanProperytRowMapper要求sql數(shù)據(jù)查詢出來的列和實(shí)體屬性需要一一對(duì)應(yīng)。如果數(shù)據(jù)中列明和屬性名不一致,在sql語句中需要用as重新取一個(gè)別名
- 使用JdbcTemplate對(duì)象不能獲取關(guān)聯(lián)對(duì)象
- 查詢結(jié)果為空時(shí),Spring不會(huì)返回null,而是拋出org.springframework.dao.EmptyResultDataAccessException異常
JdbcDaoSupport類
public class GenericDaoImpl extends JdbcDaoSupport implements GenericDao {
@Autowired
public void setDataSource(DriverManagerDataSource dataSource) {
super.setDataSource(dataSource);
}
}
------------------------------------------------------------------------------------------------
//使自己的dao類直接或間接繼承JdbcDaoSupport類,傳入dataSource對(duì)象
@Repository("deptDao")
public class DeptDaoImpl extends GenericDaoImpl implements DeptDao {
//可直接使用該方法獲取JdbcTemplate對(duì)象
this.getJdbcTemplate();
}
注:Autowired注解可以實(shí)現(xiàn)對(duì)方法形參的自動(dòng)裝配。
@Autowired將查找被標(biāo)注的方法的入?yún)㈩愋偷腂ean,并調(diào)用方法自動(dòng)注入
Spring事務(wù)管理
Spring的聲明式事務(wù)管理策略
Spring的事務(wù)管理建立在AOP基礎(chǔ)之上,其本質(zhì)是對(duì)目標(biāo)方法執(zhí)行前后進(jìn)行攔截,在目標(biāo)方法開始執(zhí)行之前加入事務(wù),在執(zhí)行完目標(biāo)方法之后根據(jù)執(zhí)行情況(執(zhí)行成功則提交,收到異常信息則回滾)處理事務(wù)。事務(wù)管理本身就是一個(gè)典型的AOP切面。
優(yōu)點(diǎn):代碼耦合程度低,復(fù)用性強(qiáng)。
注意:實(shí)施事務(wù)的方法的修飾符必須是public,其它private、static、final均不可,否則不能使用AOP動(dòng)態(tài)代理啟動(dòng)事務(wù)
1.配置Spring事務(wù)管理
<aop:aspectj-autoproxy />
<context:component-scan base-package="com" />
<!--配置事務(wù)管理器-->
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!—為事務(wù)管理器注冊(cè)注解驅(qū)動(dòng)器-->
<tx:annotation-driven transaction-manager="txManager"/>
2.在service中加入事務(wù)控制
@Service("deptService")
//加入開啟事務(wù)注解
@Transactional
public class DeptServiceImpl extends GenericServiceImpl implements DeptService {
@Autowired
private DeptDao deptDao;
public DeptDao getDeptDao() {
return deptDao;
}
public void setDeptDao(DeptDao deptDao) {
this.deptDao = deptDao;
}
//對(duì)不涉及寫數(shù)據(jù)庫寫入操作的方法,可加入只讀屬性以提高速度
@Transactional(readOnly = true)
public List<Dept> findAll() {
return this.deptDao.findAll();
}
public void add() {
Dept d1 = new Dept(50, "中國銷售部", "濟(jì)南");
Dept d2 = new Dept(50, "中國研發(fā)部", "北京");
this.deptDao.insert(d1);
this.deptDao.insert(d2);
}
}
@Transactional注解常用屬性
| 屬性 | 類型 | 默認(rèn)值 | 說明 |
|---|---|---|---|
| propagation | Propagation枚舉 | REQUIRED | 事務(wù)傳播屬性 |
| isolation | isolation枚舉 | DEFAULT | 指定事務(wù)隔離級(jí)別。取值有ISOLATION_DEFAULT(默認(rèn)值,使用數(shù)據(jù)庫默認(rèn)的事務(wù)隔離級(jí)別)、READ_UNCOMMITTED、READ_COMMITTED、REPEATABLE_READ、SERIALIZABLE。 |
| readOnly | boolean | false | 是否只讀。”只讀事務(wù)”提示數(shù)據(jù)庫驅(qū)動(dòng)程序和數(shù)據(jù)庫系統(tǒng),這個(gè)事務(wù)并不包含更改數(shù)據(jù)的操作,JDBC驅(qū)動(dòng)程序和數(shù)據(jù)庫可以根據(jù)這種情況對(duì)該事務(wù)進(jìn)行一些特定的優(yōu)化,不啟動(dòng)數(shù)據(jù)庫鎖。 |
| timeout | int | -1 | 指定事務(wù)超時(shí)時(shí)間(以秒為單位),-1意味著不超時(shí)。 |
| rollbackFor | Class[] | {} | 指定觸發(fā)事務(wù)回滾的異常類(應(yīng)使用全限定類名),該屬性可指定多個(gè)異常類,多個(gè)異常類之間以英文逗號(hào)隔開。 |
| rollbackForClassName | String[] | {} | 需要回滾的異常類名 |
| noRollbackFor | Class[] | {} | 指定不觸發(fā)事務(wù)回滾的異常類(應(yīng)使用全限定類名),該屬性可指定多個(gè)異常類,多個(gè)異常類之間以英文逗號(hào)隔開。 |
| noRollbackForClassName | String[] | {} | 不需要回滾的異常類名 |
事務(wù)傳播屬性
| REQUIRED | 業(yè)務(wù)方法需要在一個(gè)事務(wù)中運(yùn)行,如果方法運(yùn)行時(shí),已處在一個(gè)事務(wù)中,那么就加入該事務(wù),否則自己創(chuàng)建一個(gè)新的事務(wù).這是****spring****默認(rèn)的傳播行為****. |
|---|---|
| SUPPORTS | 如果業(yè)務(wù)方法在某個(gè)事務(wù)范圍內(nèi)被調(diào)用,則方法成為該事務(wù)的一部分,如果業(yè)務(wù)方法在事務(wù)范圍外被調(diào)用,則方法在沒有事務(wù)的環(huán)境下執(zhí)行. |
| MANDATORY | 只能在一個(gè)已存在事務(wù)中執(zhí)行,業(yè)務(wù)方法不能發(fā)起自己的事務(wù),如果業(yè)務(wù)方法在沒有事務(wù)的環(huán)境下調(diào)用,就拋異常 |
| REQUIRES_NEW | 業(yè)務(wù)方法總是會(huì)為自己發(fā)起一個(gè)新的事務(wù),如果方法已運(yùn)行在一個(gè)事務(wù)中,則原有事務(wù)被掛起,新的事務(wù)被創(chuàng)建,直到方法結(jié)束,新事務(wù)才結(jié)束,原先的事務(wù)才會(huì)恢復(fù)執(zhí)行. |
| NOT_SUPPORTED | 聲明方法需要事務(wù),如果方法沒有關(guān)聯(lián)到一個(gè)事務(wù),容器不會(huì)為它開啟事務(wù).如果方法在一個(gè)事務(wù)中被調(diào)用,該事務(wù)會(huì)被掛起,在方法調(diào)用結(jié)束后,原先的事務(wù)便會(huì)恢復(fù)執(zhí)行. |
| NEVER | 聲明方法絕對(duì)不能在事務(wù)范圍內(nèi)執(zhí)行,如果方法在某個(gè)事務(wù)范圍內(nèi)執(zhí)行,容器就拋異常.只有沒關(guān)聯(lián)到事務(wù),才正常執(zhí)行. |
| NESTED | 如果一個(gè)活動(dòng)的事務(wù)存在,則運(yùn)行在一個(gè)嵌套的事務(wù)中.如果沒有活動(dòng)的事務(wù),則按REQUIRED屬性執(zhí)行.它使用了一個(gè)單獨(dú)的事務(wù), 這個(gè)事務(wù)擁有多個(gè)可以回滾的保證點(diǎn).內(nèi)部事務(wù)回滾不會(huì)對(duì)外部事務(wù)造成影響, 它只對(duì)DataSourceTransactionManager 事務(wù)管理器起效. |