一罕偎、JdbcTemplate:
1很澄、使用之前,需要導入的jar包:
spring-jdbc-5.0.2.RELEASE.jar
spring-tx-5.0.2.RELEASE.jar
2颜及、spring的事務(wù)控制的API:
<1>甩苛、PlatformTransactionManager:
(1)、作用:
該接口是提供事務(wù)操作的方法俏站。
(2)讯蒲、具體操作方法:
①、獲取事務(wù)狀態(tài)信息:
TransactionStatus getTransaction(TransactionDefinition definition)
②肄扎、提交事務(wù):
void commit(TransactionStatus status)
③墨林、回滾事務(wù):
void rollback(TransactionStatus status)
(2)赁酝、具體管理事務(wù)(實現(xiàn)類)的對象:
①、使用Spring JDBC或iBatis進行持久化數(shù)據(jù)時使用:
org.springframework.jdbc.datasource.DataSourceTransactionManager旭等、
②酌呆、使用Hibernate版本進行持久化數(shù)據(jù)時使用:
org.springframework.orm.hibernationManager
<2>、TransactionDefinition:
(1)搔耕、作用:
該接口是提供事務(wù)定義的對象隙袁。
(2)、具體操作方法:
①度迂、獲取事務(wù)對象名稱:
String getName()
②藤乙、獲取事務(wù)隔離級別:
Ⅰ、方法名:
int getIsolationLevel()
Ⅱ惭墓、方法參數(shù):
ISOLATION_DEFAULT:默認級別,歸屬下面某一種而姐。
ISOLATION_READ_UNCOMMITTED:可以讀未提交數(shù)據(jù)
ISOLATION_READ_COMMITTED只能讀取已提交數(shù)據(jù)腊凶,解決臟讀問題(Oracle默認級別)
ISOLATION_REPETABLE_READ:是否讀取其他事務(wù)提交修改后的數(shù)據(jù),解決不可重復(fù)讀問題(MYSQL默認級別)
ISOLATION_SERIALIZABLE:是否讀取其他事務(wù)提交添加后的數(shù)據(jù)拴念,解決幻讀問題
③钧萍、獲取事務(wù)傳播行為:
Ⅰ、方法名:
int getPropagationBehavior()
Ⅱ政鼠、方法參數(shù):
REQUIRED:如果當前沒有事務(wù)风瘦,就新建一個事務(wù),如果已經(jīng)存在一個事務(wù)中公般,就加入到該事務(wù)中万搔。一般的選擇,默認值官帘。
SUPPORTS:支持當前事務(wù)瞬雹,如果當前沒有事務(wù),就以非事務(wù)方式執(zhí)行(沒有事務(wù))
MANDATORY:使用當前的事務(wù)刽虹,如果當前沒有事務(wù)酗捌,就拋出異常。
REQUERS_NEW:新建事務(wù)涌哲,如果當前在事務(wù)中胖缤,就把當前事務(wù)掛起。
NOT_SUPPORTED:以非事務(wù)方式執(zhí)行操作阀圾,如果當前存在事務(wù)哪廓,就把當前事務(wù)掛起。
NEVER:以非事務(wù)方式運行稍刀,如果當前存在事務(wù)撩独,就拋出異常敞曹。
NESTED:如果當前存在事務(wù),則在嵌套事務(wù)內(nèi)執(zhí)行综膀;如果沒有事務(wù)澳迫,則執(zhí)行REQUIRED類似的操作。
④剧劝、獲取事務(wù)超時時間:
Ⅰ橄登、方法名:
int getTimeout()
Ⅱ、方法參數(shù):
默認值是-1讥此,沒有超時限制拢锹。如果有,以秒為單位進行設(shè)置萄喳。
⑤卒稳、獲取事務(wù)是否只讀:
Ⅰ、方法名:
boolean isReadOnly()
Ⅱ他巨、方法參數(shù):
建議查詢時設(shè)置為只讀充坑。
<3>、TransactionStatus:
(1)染突、作用:
描述了某個時間點上事務(wù)對象的狀態(tài)信息捻爷。
(2)、具體操作方法:
①份企、刷新事務(wù):
void flush()
②也榄、獲取是否存在存儲點:
boolean hasSavepoint()
③、獲取事務(wù)是否完成:
boolean isCompleted()
④司志、獲取事務(wù)是否為新事務(wù):
boolean isNewTransaction()
⑤甜紫、獲取事務(wù)是否回滾:
boolean isRollbackOnly()
⑥、設(shè)置事務(wù)回滾:
void setRollbackOnly()
二俐芯、配置:
1棵介、在XML中配置JdbcTemplate的方法:
<!--配置JdbcTemplate-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
2、JdbcTemplate的操作:
<1>吧史、獲取容器:
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
<2>邮辽、獲取對象:
JdbcTemplate jt = ac.getBean("jdbcTemplate",JdbcTemplate.class);
<3>、保存操作:
jt.update("insert into account(name,money)values(?,?)","ttt",3333f);
<4>贸营、更新操作:
jt.update("update account set name = ?,money = ? where id = ?;","aaa",1234,1);
<5>吨述、刪除操作:
jt.update("delete from account where id = ?",11);
<6>、查詢所有:
List<Account> accounts1 =
jt.query("select * from account where money > ?", new AccountRowMapper(),4000f);
List<Account> accounts2 =
jt.query("select * from account where money > ?", new BeanPropertyRowMapper<Account>(Account.class),4000f);
for(Account account : accounts1){
System.out.println(account);
}
<7>钞脂、查詢一個:
List<Account> accounts =
jt.query("select * from account where money > ?", new BeanPropertyRowMapper<Account>(Account.class),4000f);
System.out.println(accounts.isEmpty()? "沒有內(nèi)容" : accounts.get(0));
<8>揣云、查詢返回一行一列(使用聚會函數(shù),但不加group by子句):
Long count = jt.queryForObject("Select count(*) from account where money > ?",Long.class,1000f);
System.out.println(count);
2冰啃、pring中基于xml的聲明式事務(wù)配置步驟:
<1>.配置事務(wù)管理器:
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<2>.配置事務(wù)通知:
(1)邓夕、注意:
此時需要導入事務(wù)的約束;包括tx的名稱空間和約束刘莹,aop的名稱空間和約束。
(2)焚刚、使用tx:advice標簽配置事務(wù)通知時:
id:給事務(wù)通知起一個唯一id
transaction-manager:給事務(wù)通知提供一個事務(wù)管理引用
(3)点弯、配置代碼:
<tx:advice id="teAdvice" transaction-manager="transactionManager">
<!--配置事務(wù)屬性-->
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" read-only="false"/>
<tx:method name="find*" propagation="SUPPORTS" read-only="true"/>
</tx:attributes>
</tx:advice>
<3>、配置AOP中的通用切入點表達式:
<aop:config>
<!--配置切入點表達式-->
<aop:pointcut id="pt1" expression="execution(* com.itheima.service.impl.*.*(..))"></aop:pointcut>
<!--建立切入點表達式和事務(wù)通知的對應(yīng)關(guān)系-->
<aop:advisor advice-ref="teAdvice" pointcut-ref="pt1"></aop:advisor>
</aop:config>
<4>矿咕、配置事務(wù)屬性:
(1)抢肛、注意:
在事務(wù)的通知tx:Advice標簽內(nèi)部配。
(2)碳柱、tx:method標簽屬性:
①捡絮、isolation="" :
用于指定事務(wù)的隔離級別,默認值是default莲镣,表示使用數(shù)據(jù)庫的隔離屬性
②福稳、propagation="" :
用于指定事務(wù)的傳播行為。默認值REQUIRED剥悟,表示一定會有事務(wù)灵寺。增刪改的選擇。查詢方法可以選SUPPORTS区岗。
③、read-only="" :
用于指定事務(wù)是否只讀毁枯。只有查詢方法才能設(shè)置為True慈缔,默認值是false,表示讀寫种玛。
④藐鹤、timeout="":
用于指定事務(wù)的超時時間。默認值是-1赂韵,表示永不超時娱节。如果指定了數(shù)值,以秒為單位祭示。
⑤肄满、rollback-for="" :
用于指定一個異常,當產(chǎn)生該異常時质涛,事務(wù)回滾稠歉,產(chǎn)生其他異常時,事務(wù)都不回滾汇陆。沒有默認值怒炸,表示任何異常都回滾。
⑥毡代、no-rollback-for="" :
用于指定一個異常阅羹,當產(chǎn)生該異常時勺疼,事務(wù)不回滾,產(chǎn)生其他異常時捏鱼,事務(wù)回滾执庐。沒有默認值,表示任何異常都回滾穷躁。
<5>.配置數(shù)據(jù)源:
//1.準備數(shù)據(jù)源耕肩,spring的內(nèi)置數(shù)據(jù)源
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/eesy");
ds.setUsername("root");
ds.setPassword("123456");
//2.創(chuàng)建對象
JdbcTemplate jt = new JdbcTemplate();
//3.給對象設(shè)置數(shù)據(jù)源
jt.setDataSource(ds);
//3.執(zhí)行操作
jt.execute("insert into account(name,money)values('SSS',2222)");
3、pring中基于注解的聲明式事務(wù)配置步驟:
<1>.配置要掃描的包:
<context:component-scan base-package="com.itheima"></context:component-scan>
<2>.配置JdbcTemplate:
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<3>.配置數(shù)據(jù)源:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/eesy"></property>
<property name="username" value="root"></property>
<property name="password" value="123456"></property>
</bean>
<4>.配置事務(wù)管理器:
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<5>.開啟spring對注解事務(wù)的支持:
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
<6>.在需要事務(wù)支持的地方使用@Transaal注解:
//只讀型事務(wù)配置问潭,配置在類上
@Transactional(propagation = Propagation.SUPPORTS,readOnly = true)
//讀寫型事務(wù)配置猿诸,配置在方法上
@Transactional(propagation = Propagation.REQUIRED,readOnly = false)
三、配置完全代碼:
1狡忙、基于XML的配置:
<1>梳虽、在JdbcTemplate類中:
public class JdbcTemplateDemo1 {
public static void main(String[] args) {
//1.準備數(shù)據(jù)源,spring的內(nèi)置數(shù)據(jù)源
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/eesy");
ds.setUsername("root");
ds.setPassword("123456");
//2.創(chuàng)建對象
JdbcTemplate jt = new JdbcTemplate();
//3.給對象設(shè)置數(shù)據(jù)源
jt.setDataSource(ds);
//3.執(zhí)行操作
jt.execute(SQL操作語句");
}
}
<2>灾茁、在bean.xml中:
bean.xml中:
<!--配置業(yè)務(wù)層-->
<bean id="accountService" class="com.itheima.service.impl.AccountService">
<property name="accountDao" ref="accountDao"></property>
</bean>
<!--配置賬戶持久層-->
<bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置數(shù)據(jù)源-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/eesy"></property>
<property name="username" value="root"></property>
<property name="password" value="123456"></property>
</bean>
<!--配置事務(wù)管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置事務(wù)通知-->
<tx:advice id="teAdvice" transaction-manager="transactionManager">
<!--配置事務(wù)屬性-->
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" read-only="false"/>
<tx:method name="find*" propagation="SUPPORTS" read-only="true"/>
</tx:attributes>
</tx:advice>
<!--配置AOP-->
<aop:config>
<!--配置切入點表達式-->
<aop:pointcut id="pt1" expression="execution(* com.itheima.service.impl.*.*(..))"></aop:pointcut>
<!--建立切入點表達式和事務(wù)通知的對應(yīng)關(guān)系-->
<aop:advisor advice-ref="teAdvice" pointcut-ref="pt1"></aop:advisor>
</aop:config>
<3>窜觉、Service層:
public class AccountService implements IAccountService {
private IAccountDao accountDao;
public void setAccountDao(IAccountDao accountDao) {
this.accountDao = accountDao;
}
public Account findAccountById(Integer accountId) {
return accountDao.findAccountById(accountId);
}
public void transfer(String sourceName, String targetName, Float money) {
System.out.println("transfer!!!");
//根據(jù)名稱查詢轉(zhuǎn)出賬戶
Account source = accountDao.findAccountByName(sourceName);
//根據(jù)名稱查詢轉(zhuǎn)入賬戶
Account target = accountDao.findAccountByName(targetName);
//轉(zhuǎn)出賬戶減錢
source.setMoney(source.getMoney() - money);
//轉(zhuǎn)入賬戶加錢
target.setMoney(target.getMoney() + money);
//更新轉(zhuǎn)出賬戶
accountDao.updateAccount(source);
//更新轉(zhuǎn)入賬戶
accountDao.updateAccount(target);
}
}
<4>、Dao層:
public class AccountDaoImpl extends JdbcDaoSupport implements IAccountDao {
public Account findAccountById(Integer accountId) {
List<Account> accounts = super.
getJdbcTemplate().query("select * from account where money > ?", new BeanPropertyRowMapper<Account>(Account.class), accountId);
return accounts.isEmpty() ? null : accounts.get(0);
}
public Account findAccountByName(String accountName) {
List<Account> accounts = super.
getJdbcTemplate().query("select * from account where name = ?", new BeanPropertyRowMapper<Account>(Account.class),accountName);
if(accounts.isEmpty()){
return null;
}
if(accounts.size() > 1){
throw new RuntimeException("結(jié)果集不唯一1弊āY鞔臁!");
}
return accounts.get(0);
}
public void updateAccount(Account account) {
super.getJdbcTemplate().update("update account set name = ?,money = ? where id = ?",account.getName(),account.getMoney(),account.getId());
}
}
<5>拓颓、定義account的封裝策略:
class AccountRowMapper implements RowMapper<Account>{
/**
* 把結(jié)果集中的數(shù)據(jù)封裝到account中语婴,然后由spring把每個Account加到集合中
* @param rs
* @param i
* @return
* @throws SQLException
*/
public Account mapRow(ResultSet rs, int i) throws SQLException {
Account account = new Account();
account.setId(rs.getInt("id"));
account.setName(rs.getString("name"));
account.setMoney(rs.getFloat("money"));
return account;
}
2、基于注解的配置:
<1>驶睦、在bean.xml中:
<!--配置要掃描的包-->
<context:component-scan base-package="com.itheima"></context:component-scan>
<!--配置JdbcTemplate-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置數(shù)據(jù)源-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/eesy"></property>
<property name="username" value="root"></property>
<property name="password" value="123456"></property>
</bean>
<!--配置事務(wù)管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--開啟spring對注解事務(wù)的支持-->
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
<2>砰左、Service層:
@Service("accountService")
//只讀型事務(wù)配置
@Transactional(propagation = Propagation.SUPPORTS,readOnly = true)
public class AccountServiceImpl implements IAccountService {
@Autowired
private IAccountDao accountDao;
public Account findAccountById(Integer accountId) {
return accountDao.findAccountById(accountId);
}
//讀寫型事務(wù)配置
@Transactional(propagation = Propagation.REQUIRED,readOnly = false)
public void transfer(String sourceName, String targetName, Float money) {
System.out.println("transfer!!!");
//根據(jù)名稱查詢轉(zhuǎn)出賬戶
Account source = accountDao.findAccountByName(sourceName);
//根據(jù)名稱查詢轉(zhuǎn)入賬戶
Account target = accountDao.findAccountByName(targetName);
//轉(zhuǎn)出賬戶減錢
source.setMoney(source.getMoney() - money);
//轉(zhuǎn)入賬戶加錢
target.setMoney(target.getMoney() + money);
//更新轉(zhuǎn)出賬戶
accountDao.updateAccount(source);
int i = 1/0;
//更新轉(zhuǎn)入賬戶
accountDao.updateAccount(target);
}
}
<3>、Dao層:
@Repository("accountDao")
public class AccountDaoImpl implements IAccountDao {
@Autowired
private JdbcTemplate jdbcTemplate;
public Account findAccountById(Integer accountId) {
List<Account> accounts = jdbcTemplate.query("select * from account where money > ?", new BeanPropertyRowMapper<Account>(Account.class), accountId);
return accounts.isEmpty() ? null : accounts.get(0);
}
public Account findAccountByName(String accountName) {
List<Account> accounts = jdbcTemplate.query("select * from account where name = ?", new BeanPropertyRowMapper<Account>(Account.class),accountName);
if(accounts.isEmpty()){
return null;
}
if(accounts.size() > 1){
throw new RuntimeException("結(jié)果集不唯一3『健2肌!");
}
return accounts.get(0);
}
public void updateAccount(Account account) {
jdbcTemplate.update("update account set name = ?,money = ? where id = ?",account.getName(),account.getMoney(),account.getId());
}
}
<4>溉痢、JdbcTemplate:
public class JdbcTemplateDemo1 {
public static void main(String[] args) {
//1.準備數(shù)據(jù)源僻造,spring的內(nèi)置數(shù)據(jù)源
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/eesy");
ds.setUsername("root");
ds.setPassword("123456");
//2.創(chuàng)建對象
JdbcTemplate jt = new JdbcTemplate();
//3.給對象設(shè)置數(shù)據(jù)源
jt.setDataSource(ds);
//3.執(zhí)行操作
jt.execute("insert into account(name,money)values('SSS',2222)");
}
}