SSH框架之Spring第四篇
- 2019 年 10 月 6 日
- 筆記
版權聲明:本文為部落客原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
本文鏈接:https://blog.csdn.net/zhao1299002788/article/details/101168019
1.1 JdbcTemplate概述 : 它是spring框架中提供的一個對象,是對原始JdbcAPI對象的簡單封裝.spring框架為我們提供了很多的操作模板類. ORM持久化技術 模板類 JDBC org.springframework.jdbc.core.JdbcTemplate. Hibernate3.0 org.springframework.orm.hibernate3.HibernateTemplate. IBatis(MyBatis) org.springframework.orm.ibatis.SqlMapClientTemplate. JPA org.springframework.orm.jpa.JpaTemplate. 在導包的時候需要導入spring-jdbc-4.24.RELEASF.jar,還需要導入一個spring-tx-4.2.4.RELEASE.jar(它和事務有關) <!-- 配置數據源 --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"></property> <property name="url" value="jdbc:mysql:// /spring_day04"></property> <property name="username" value="root"></property> <property name="password" value="1234"></property> </bean> 1.3.3.3配置spring內置數據源 spring框架也提供了一個內置數據源,我們也可以使用spring的內置數據源,它就在spring-jdbc-4.2.4.REEASE.jar包中: <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"></property> <property name="url" value="jdbc:mysql:///spring_day04"></property> <property name="username" value="root"></property> <property name="password" value="1234"></property> </bean> 1.3.4將資料庫連接的資訊配置到屬性文件中: 【定義屬性文件】 jdbc.driverClass=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql:///spring_day02 jdbc.username=root jdbc.password=123 【引入外部的屬性文件】 一種方式: <!-- 引入外部屬性文件: --> <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location" value="classpath:jdbc.properties"/> </bean> 二種方式: <context:property-placeholder location="classpath:jdbc.properties"/> 1.4JdbcTemplate的增刪改查操作 1.4.1前期準備 創建資料庫: create database spring_day04; use spring_day04; 創建表: create table account( id int primary key auto_increment, name varchar(40), money float )character set utf8 collate utf8_general_ci; 1.4.2在spring配置文件中配置JdbcTemplate <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 配置一個資料庫的操作模板:JdbcTemplate --> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 配置數據源 --> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"></property> <property name="url" value="jdbc:mysql:///spring_day04"></property> <property name="username" value="root"></property> <property name="password" value="1234"></property> </bean> </beans> 1.4.3最基本使用 public class JdbcTemplateDemo2 { public static void main(String[] args) { //1.獲取Spring容器 ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml"); //2.根據id獲取bean對象 JdbcTemplate jt = (JdbcTemplate) ac.getBean("jdbcTemplate"); //3.執行操作 jt.execute("insert into account(name,money)values('eee',500)"); } } 1.4.4保存操作 public class JdbcTemplateDemo3 { public static void main(String[] args) { //1.獲取Spring容器 ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml"); //2.根據id獲取bean對象 JdbcTemplate jt = (JdbcTemplate) ac.getBean("jdbcTemplate"); //3.執行操作 //保存 jt.update("insert into account(name,money)values(?,?)","fff",5000); } } 1.4.5更新操作 public class JdbcTemplateDemo3 { public static void main(String[] args) { //1.獲取Spring容器 ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml"); //2.根據id獲取bean對象 JdbcTemplate jt = (JdbcTemplate) ac.getBean("jdbcTemplate"); //3.執行操作 //修改 jt.update("update account set money = money-? where id = ?",300,6); } } 1.4.6刪除操作 public class JdbcTemplateDemo3 { public static void main(String[] args) { //1.獲取Spring容器 ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml"); //2.根據id獲取bean對象 JdbcTemplate jt = (JdbcTemplate) ac.getBean("jdbcTemplate"); //3.執行操作 //刪除 jt.update("delete from account where id = ?",6); } } 1.4.7查詢所有操作 public class JdbcTemplateDemo3 { public static void main(String[] args) { //1.獲取Spring容器 ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml"); //2.根據id獲取bean對象 JdbcTemplate jt = (JdbcTemplate) ac.getBean("jdbcTemplate"); //3.執行操作 //查詢所有 List<Account> accounts = jt.query("select * from account where money > ? ", new AccountRowMapper(), 500); for(Account o : accounts){ System.out.println(o); } } } public class AccountRowMapper implements RowMapper<Account>{ @Override public Account mapRow(ResultSet rs, int rowNum) throws SQLException { Account account = new Account(); account.setId(rs.getInt("id")); account.setName(rs.getString("name")); account.setMoney(rs.getFloat("money")); return account; } } 1.4.8查詢一個操作 使用RowMapper的方式:常用的方式 public class JdbcTemplateDemo3 { public static void main(String[] args) { //1.獲取Spring容器 ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml"); //2.根據id獲取bean對象 JdbcTemplate jt = (JdbcTemplate) ac.getBean("jdbcTemplate"); //3.執行操作 //查詢一個 List<Account> as = jt.query("select * from account where id = ? ", new AccountRowMapper(), 55); System.out.println(as.isEmpty()?"沒有結果":as.get(0)); } } 1.4.9查詢返回一行一列操作 public class JdbcTemplateDemo3 { public static void main(String[] args) { //1.獲取Spring容器 ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml"); //2.根據id獲取bean對象 JdbcTemplate jt = (JdbcTemplate) ac.getBean("jdbcTemplate"); //3.執行操作 //查詢返回一行一列:使用聚合函數,在不使用group by字句時,都是返回一行一列。最長用的就是分頁中獲取總記錄條數 Integer total = jt.queryForObject("select count(*) from account where money > ? ",Integer.class,500); System.out.println(total); } } applicationContext.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!-- 使用Spring管理連接池對象,Spring內置的連接池對象 --> <!-- <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"></property> <property name="url" value="jdbc:mysql:///spring_04"/> <property name="username" value="root"></property> <property name="password" value="root"></property> </bean> --> <!-- 配置數據源,使用Spring整合dbcp連接,沒有導入jar包 --> <!-- <bean id="dataSource" class="org.apache.tomcat.dbcp.dbcp.BasicDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql:///spring_04"/> <property name="username" value="root"/> <property name="password" value="root"/> </bean> --> <!-- 使用Spring整合c3p0的連接池,沒有採用屬性文件的方式 --> <!-- <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.jdbc.Driver"/> <property name="jdbcUrl" value="jdbc:mysql:///spring_04"/> <property name="user" value="root"/> <property name="password" value="root"/> </bean> --> <!-- 使用context:property-placeholder標籤,讀取屬性文件 --> <context:property-placeholder location="classpath:db.properties"/> <!-- 使用Spring整合c3p0的連接池,採用屬性文件的方式 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc.driver}"/> <property name="jdbcUrl" value="${jdbc.url}"/> <property name="user" value="${jdbc.user}"/> <property name="password" value="${jdbc.password}"/> </bean> <!-- spring管理JbdcTemplate模板 --> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"/> </bean> </beans> db.properties : 屬性文件 jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql:///spring_day04 jdbc.user=root jdbc.password=root Demo測試 : package com.ithiema.demo1; import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; import javax.annotation.Resource; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; /** * Spring整合JdbcTemplate的方式入門 * @author Administrator */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class Demo11 { @Resource(name="jdbcTemplate") private JdbcTemplate jdbcTemplate; /** * 添加 */ @Test public void run1(){ jdbcTemplate.update("insert into account values (null,?,?)", "嘿嘿",10000); } /** * 修改 */ @Test public void run2(){ jdbcTemplate.update("update account set name = ?,money = ? where id = ?", "嘻嘻",5000,6); } /** * 刪除 */ @Test public void run3(){ jdbcTemplate.update("delete from account where id = ?", 6); } /** * 查詢多條數據 */ @Test public void run4(){ // sql sql語句 // rowMapper 提供封裝數據的介面,自己提供實現類(自己封裝數據的) List<Account> list = jdbcTemplate.query("select * from account", new BeanMapper()); for (Account account : list) { System.out.println(account); } } } /** * 自己封裝的實現類,封裝數據的 * @author Administrator */ class BeanMapper implements RowMapper<Account>{ /** * 一行一行封裝數據的 */ public Account mapRow(ResultSet rs, int index) throws SQLException { // 創建Account對象,一個屬性一個屬性賦值,返回對象 Account ac = new Account(); ac.setId(rs.getInt("id")); ac.setName(rs.getString("name")); ac.setMoney(rs.getDouble("money")); return ac; } } 2,1 Spring 事務控制我們要明確的 1: JavaEE體系進行分層開發,事務處理位於業務層,Spring提供了分層設計業務層的事務處理解決方案. 2: Spring框架為我們提供就一組事務控制的介面.這組介面是在spring-tx-4.2.4RELEASE.jar中. 3: spring的事務都是基於AOP的,它既可以使用編程的方式實現,也可以使用配置的方式實現 2.2Spring中事務控制的API介紹 2.2.1PlatformTransactionManager 此介面是spring的事務管理器,它裡面提供了我們常用的操作事務的方法,如下圖: 我們在開發中都是使用它的實現類,如下圖: 真正管理事務的對象 org.springframework.jdbc.datasource.DataSourceTransactionManager 使用Spring JDBC或iBatis 進行持久化數據時使用 org.springframework.orm.hibernate3.HibernateTransactionManager 使用Hibernate版本進行持久化數據時使用 2.2.2TransactionDefinition 它是事務的定義資訊對象,裡面有如下方法: 2.2.2.1事務的隔離級別 2.2.2.2事務的傳播行為 REQUIRED:如果當前沒有事務,就新建一個事務,如果已經存在一個事務中,加入到這個事務中。一般的選擇(默認值) SUPPORTS:支援當前事務,如果當前沒有事務,就以非事務方式執行(沒有事務) MANDATORY:使用當前的事務,如果當前沒有事務,就拋出異常 REQUERS_NEW:新建事務,如果當前在事務中,把當前事務掛起。 NOT_SUPPORTED:以非事務方式執行操作,如果當前存在事務,就把當前事務掛起 NEVER:以非事務方式運行,如果當前存在事務,拋出異常 NESTED:如果當前存在事務,則在嵌套事務內執行。如果當前沒有事務,則執行REQUIRED類似的操作。 2.2.2.3超時時間 默認值是-1,沒有超時限制。如果有,以秒為單位進行設置。 2.2.2.4是否是只讀事務 建議查詢時設置為只讀。 2.2.3TransactionStatus 此介面提供的是事務具體的運行狀態,方法介紹如下圖: 2.3基於XML的聲明式事務控制(配置方式)重點 2.3.1環境搭建 2.3.1.1第一步:拷貝必要的jar包到工程的lib目錄 2.3.1.2第二步:創建spring的配置文件並導入約束 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> </beans> 2.3.1.3第三步:準備資料庫表和實體類 創建資料庫: create database spring_day04; use spring_day04; 創建表: create table account( id int primary key auto_increment, name varchar(40), money float )character set utf8 collate utf8_general_ci; /** * 賬戶的實體 */ public class Account implements Serializable { private Integer id; private String name; private Float money; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Float getMoney() { return money; } public void setMoney(Float money) { this.money = money; } @Override public String toString() { return "Account [id=" + id + ", name=" + name + ", money=" + money + "]"; } } 2.3.1.4第四步:編寫業務層介面和實現類 /** * 賬戶的業務層介面 */ public interface IAccountService { /** * 根據id查詢賬戶資訊 * @param id * @return */ Account findAccountById(Integer id);//查 /** * 轉賬 * @param sourceName 轉出賬戶名稱 * @param targeName 轉入賬戶名稱 * @param money 轉賬金額 */ void transfer(String sourceName,String targeName,Float money);//增刪改 } /** * 賬戶的業務層實現類 */ public class AccountServiceImpl implements IAccountService { private IAccountDao accountDao; public void setAccountDao(IAccountDao accountDao) { this.accountDao = accountDao; } @Override public Account findAccountById(Integer id) { return accountDao.findAccountById(id); } @Override public void transfer(String sourceName, String targeName, Float money) { //1.根據名稱查詢兩個賬戶 Account source = accountDao.findAccountByName(sourceName); Account target = accountDao.findAccountByName(targeName); //2.修改兩個賬戶的金額 source.setMoney(source.getMoney()-money);//轉出賬戶減錢 target.setMoney(target.getMoney()+money);//轉入賬戶加錢 //3.更新兩個賬戶 accountDao.updateAccount(source); int i=1/0; accountDao.updateAccount(target); } } 2.3.1.5第五步:編寫Dao介面和實現類 /** * 賬戶的持久層介面 */ public interface IAccountDao { /** * 根據id查詢賬戶資訊 * @param id * @return */ Account findAccountById(Integer id); /** * 根據名稱查詢賬戶資訊 * @return */ Account findAccountByName(String name); /** * 更新賬戶資訊 * @param account */ void updateAccount(Account account); } /** * 賬戶的持久層實現類 * 此版本dao,只需要給它的父類注入一個數據源 */ public class AccountDaoImpl extends JdbcDaoSupport implements IAccountDao { @Override public Account findAccountById(Integer id) { List<Account> list = getJdbcTemplate().query("select * from account where id = ? ",new AccountRowMapper(),id); return list.isEmpty()?null:list.get(0); } @Override public Account findAccountByName(String name) { List<Account> list = getJdbcTemplate().query("select * from account where name = ? ",new AccountRowMapper(),name); if(list.isEmpty()){ return null; } if(list.size()>1){ throw new RuntimeException("結果集不唯一,不是只有一個賬戶對象"); } return list.get(0); } @Override public void updateAccount(Account account) { getJdbcTemplate().update("update account set money = ? where id = ? ",account.getMoney(),account.getId()); } } /** * 賬戶的封裝類RowMapper的實現類 */ public class AccountRowMapper implements RowMapper<Account>{ @Override public Account mapRow(ResultSet rs, int rowNum) throws SQLException { Account account = new Account(); account.setId(rs.getInt("id")); account.setName(rs.getString("name")); account.setMoney(rs.getFloat("money")); return account; } } 2.3.1.6第六步:在配置文件中配置業務層和持久層對 <!-- 配置service --> <bean id="accountService" class="com.baidu.service.impl.AccountServiceImpl"> <property name="accountDao" ref="accountDao"></property> </bean> <!-- 配置dao --> <bean id="accountDao" class="com.baidu.dao.impl.AccountDaoImpl"> <!-- 注入dataSource --> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 配置數據源 --> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"></property> <property name="url" value="jdbc:mysql:///spring_day04"></property> <property name="username" value="root"></property> <property name="password" value="1234"></property> </bean> 2.3.2配置步驟 2.3.2.1第一步:配置事務管理器 <!-- 配置一個事務管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!-- 注入DataSource --> <property name="dataSource" ref="dataSource"></property> </bean> 2.3.2.2第二步:配置事務的通知引用事務管理器 <!-- 事務的配置 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> </tx:advice> 2.3.2.3第三步:配置事務的屬性 <!--在tx:advice標籤內部 配置事務的屬性 --> <tx:attributes> <!-- 指定方法名稱:是業務核心方法 read-only:是否是只讀事務。默認false,不只讀。 isolation:指定事務的隔離級別。默認值是使用資料庫的默認隔離級別。 propagation:指定事務的傳播行為。 timeout:指定超時時間。默認值為:-1。永不超時。 rollback-for:用於指定一個異常,當執行產生該異常時,事務回滾。產生其他異常,事務不回滾。沒有默認值,任何異常都回滾。 no-rollback-for:用於指定一個異常,當產生該異常時,事務不回滾,產生其他異常時,事務回滾。沒有默認值,任何異常都回滾。 --> <tx:method name="*" read-only="false" propagation="REQUIRED"/> <tx:method name="find*" read-only="true" propagation="SUPPORTS"/> </tx:attributes> 2.3.2.4第四步:配置AOP-切入點表達式 <!-- 配置aop --> <aop:config> <!-- 配置切入點表達式 --> <aop:pointcut expression="execution(* com.baidu.service.impl.*.*(..))" id="pt1"/> </aop:config> 2.3.2.5第五步:配置切入點表達式和事務通知的對應關係 <!-- 在aop:config標籤內部:建立事務的通知和切入點表達式的關係 --> <aop:advisor advice-ref="txAdvice" pointcut-ref="pt1"/> 2.4基於XML和註解組合使用的整合方式 2.4.1環境搭建 2.4.1.1第一步:拷貝必備的jar包到工程的lib目錄 2.4.1.2第二步:創建spring的配置文件導入約束並配置掃描的包 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 配置spring要掃描的包 --> <context:component-scan base-package="com.baidu"></context:component-scan> </beans> 2.4.1.3第三步:創建資料庫表和實體類 和基於xml的配置相同。 2.4.1.4第四步:創建業務層介面和實現類並使用註解讓spring管理 業務層介面和基於xml配置的時候相同。略 /** * 賬戶的業務層實現類 */ @Service("accountService") public class AccountServiceImpl implements IAccountService { @Autowired private IAccountDao accountDao; @Override public Account findAccountById(Integer id) { return accountDao.findAccountById(id); } @Override public void transfer(String sourceName, String targeName, Float money) { //1.根據名稱查詢兩個賬戶 Account source = accountDao.findAccountByName(sourceName); Account target = accountDao.findAccountByName(targeName); //2.修改兩個賬戶的金額 source.setMoney(source.getMoney()-money);//轉出賬戶減錢 target.setMoney(target.getMoney()+money);//轉入賬戶加錢 //3.更新兩個賬戶 accountDao.updateAccount(source); int i=1/0; accountDao.updateAccount(target); } } 2.4.1.5第五步:創建Dao介面和實現類並使用註解讓spring管理 Dao層介面和AccountRowMapper與基於xml配置的時候相同。略 @Repository("accountDao") public class AccountDaoImpl implements IAccountDao { @Autowired private JdbcTemplate jdbcTemplate; @Override public Account findAccountById(Integer id) { List<Account> list = jdbcTemplate.query("select * from account where id = ? ",new AccountRowMapper(),id); return list.isEmpty()?null:list.get(0); } @Override public Account findAccountByName(String name) { List<Account> list = jdbcTemplate.query("select * from account where name = ? ",new AccountRowMapper(),name); if(list.isEmpty()){ return null; } if(list.size()>1){ throw new RuntimeException("結果集不唯一,不是只有一個賬戶對象"); } return list.get(0); } @Override public void updateAccount(Account account) { jdbcTemplate.update("update account set money = ? where id = ? ",account.getMoney(),account.getId()); } } 2.4.2配置步驟 2.4.2.1第一步:配置數據源和JdbcTemplate <!-- 配置數據源 --> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"></property> <property name="url" value="jdbc:mysql:///spring_day04"></property> <property name="username" value="root"></property> <property name="password" value="1234"></property> </bean> 2.4.2.2第二步:配置事務管理器並注入數據源 <!-- 配置JdbcTemplate --> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean> 2.4.2.3第三步:在業務層使用@Transactional註解 @Service("accountService") @Transactional(readOnly=true,propagation=Propagation.SUPPORTS) public class AccountServiceImpl implements IAccountService { @Autowired private IAccountDao accountDao; @Override public Account findAccountById(Integer id) { return accountDao.findAccountById(id); } @Override @Transactional(readOnly=false,propagation=Propagation.REQUIRED) public void transfer(String sourceName, String targeName, Float money) { //1.根據名稱查詢兩個賬戶 Account source = accountDao.findAccountByName(sourceName); Account target = accountDao.findAccountByName(targeName); //2.修改兩個賬戶的金額 source.setMoney(source.getMoney()-money);//轉出賬戶減錢 target.setMoney(target.getMoney()+money);//轉入賬戶加錢 //3.更新兩個賬戶 accountDao.updateAccount(source); //int i=1/0; accountDao.updateAccount(target); } } 該註解的屬性和xml中的屬性含義一致。該註解可以出現在介面上,類上和方法上。 出現介面上,表示該介面的所有實現類都有事務支援。 出現在類上,表示類中所有方法有事務支援 出現在方法上,表示方法有事務支援。 以上三個位置的優先順序:方法>類>介面 2.4.2.4第四步:在配置文件中開啟spring對註解事務的支援 <!-- 開啟spring對註解事務的支援 --> <tx:annotation-driven transaction-manager="transactionManager"/> 2.5基於純註解的聲明式事務控制(配置方式)重點 2.5.1環境搭建 2.5.1.1第一步:拷貝必備的jar包到工程的lib目錄 2.5.1.2第二步:創建一個類用於載入spring的配置並指定要掃描的包 /** * 用於初始化spring容器的配置類 */ @Configuration @ComponentScan(basePackages="com.baidu") public class SpringConfiguration { } 2.5.1.3第三步:創建資料庫表和實體類 和基於xml的配置相同。略 2.5.1.4第四步:創建業務層介面和實現類並使用註解讓spring管理 業務層介面和基於xml配置的時候相同。略 /** * 賬戶的業務層實現類 */ @Service("accountService") public class AccountServiceImpl implements IAccountService { @Autowired private IAccountDao accountDao; @Override public Account findAccountById(Integer id) { return accountDao.findAccountById(id); } @Override public void transfer(String sourceName, String targeName, Float money) { //1.根據名稱查詢兩個賬戶 Account source = accountDao.findAccountByName(sourceName); Account target = accountDao.findAccountByName(targeName); //2.修改兩個賬戶的金額 source.setMoney(source.getMoney()-money);//轉出賬戶減錢 target.setMoney(target.getMoney()+money);//轉入賬戶加錢 //3.更新兩個賬戶 accountDao.updateAccount(source); int i=1/0; accountDao.updateAccount(target); } } 2.5.1.5第五步:創建Dao介面和實現類並使用註解讓spring管理 Dao層介面和AccountRowMapper與基於xml配置的時候相同。略 @Repository("accountDao") public class AccountDaoImpl implements IAccountDao { @Autowired private JdbcTemplate jdbcTemplate; @Override public Account findAccountById(Integer id) { List<Account> list = jdbcTemplate.query("select * from account where id = ? ",new AccountRowMapper(),id); return list.isEmpty()?null:list.get(0); } @Override public Account findAccountByName(String name) { List<Account> list = jdbcTemplate.query("select * from account where name = ? ",new AccountRowMapper(),name); if(list.isEmpty()){ return null; } if(list.size()>1){ throw new RuntimeException("結果集不唯一,不是只有一個賬戶對象"); } return list.get(0); } @Override public void updateAccount(Account account) { jdbcTemplate.update("update account set money = ? where id = ? ",account.getMoney(),account.getId()); } } 2.5.2配置步驟 2.5.2.1第一步:使用@Bean註解配置數據源 @Bean(name = "dataSource") public DataSource createDS() throws Exception { DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setUsername("root"); dataSource.setPassword("123"); dataSource.setDriverClassName("com.mysql.jdbc.Driver"); dataSource.setUrl("jdbc:mysql:///spring3_day04"); return dataSource; } 2.5.2.2第二步:使用@Bean註解配置配置事務管理器 @Bean public PlatformTransactionManager createTransactionManager(@Qualifier("dataSource") DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } 2.5.2.3第三步:使用@Bean註解配置JdbcTemplate @Bean public JdbcTemplate createTemplate(@Qualifier("dataSource") DataSource dataSource) { return new JdbcTemplate(dataSource); } 2.5.2.4第四步:在需要控制事務的業務層實現類上使用@Transactional註解 @Service("accountService") @Transactional(readOnly=true,propagation=Propagation.SUPPORTS) public class AccountServiceImpl implements IAccountService { @Autowired private IAccountDao accountDao; @Override public Account findAccountById(Integer id) { return accountDao.findAccountById(id); } @Override @Transactional(readOnly=false,propagation=Propagation.REQUIRED) public void transfer(String sourceName, String targeName, Float money) { //1.根據名稱查詢兩個賬戶 Account source = accountDao.findAccountByName(sourceName); Account target = accountDao.findAccountByName(targeName); //2.修改兩個賬戶的金額 source.setMoney(source.getMoney()-money);//轉出賬戶減錢 target.setMoney(target.getMoney()+money);//轉入賬戶加錢 //3.更新兩個賬戶 accountDao.updateAccount(source); //int i=1/0; accountDao.updateAccount(target); } } 該註解的屬性和xml中的屬性含義一致。該註解可以出現在介面上,類上和方法上。 出現介面上,表示該介面的所有實現類都有事務支援。 出現在類上,表示類中所有方法有事務支援 出現在方法上,表示方法有事務支援。 以上三個位置的優先順序:方法>類>介面。 2.5.2.5第五步:使用@EnableTransactionManagement開啟spring對註解事務的的支援 @Configuration @EnableTransactionManagement public class SpringTxConfiguration { //裡面配置數據源,配置JdbcTemplate,配置事務管理器。在之前的步驟已經寫過了。 } 在Spring中開啟事務的案例 applicationContext3.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!-- 使用Spring整合c3p0的連接池,沒有採用屬性文件的方式 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource "> <property name="driverClass" value="com.mysql.jdbc.Driver"/> <property name="jdbcUrl" value="jdbc:mysql:///spring_04"/> <property name="user" value="root"/> <property name="password" value="root"/> </bean> <!-- 配置平台事務管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 配置通知: 是Spring框架提供通知,不是咋們自己編寫的 --> <tx:advice id="myAdvice" transaction-manager="transactionManager"> <tx:attributes> <!-- 給具體的業務層的方法進行隔離級別,傳播行為的具體的配置 --> <tx:method name="pay" isolation="DEFAULT" propagation="REQUIRED"/> <tx:method name="save*" isolation="DEFAULT"></tx:method> <tx:method name="find*" read-only="true"></tx:method> </tx:attributes> </tx:advice> <!-- 配置AOP的增強 --> <aop:config> <!-- Spring框架製作的通知,必須要使用該標籤,如果是自定義的切面,使用aop:aspect標籤 --> <aop:advisor advice-ref="myAdvice" pointcut="execution(public * com.baidu.*.*ServiceImpl.*(..))"></aop:advisor> </aop:config> <!-- 可以注入連接池 --> <bean id="accountDao" class="com.baidu.demo3.AccountDaoImpl"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 管理service --> <bean id="accountService" class="com.baidu.demo3.AccountServiceImpl"> <property name="accountDao" ref="accountDao"></property> </bean> </beans> 在dao層對程式碼進行了優化,優化了JdbcTemplate public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao { /* private JdbcTemplate jdbcTemplate; public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; }*/ //減錢 @Override public void outMoney(String out, double money) { //jdbcTemplate.update("update username set money = money - ? where name = ?",money,out); this.getJdbcTemplate().update("update username set money = money - ? where name=?",money,out); } //加錢 @Override public void inMoney(String in, double money) { //jdbcTemplate.update("update username set money = money + ? where name = ?",money,in); this.getJdbcTemplate().update("update username set money = money + ? where name=?",money,in); } } Xml和註解一起進行Spring的事務管理 applicationContext4.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!-- 開啟註解的掃描 --> <context:component-scan base-package="com.baidu"/> <!-- 使用Spring整合c3p0的連接池,沒有採用屬性文件的方式 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.jdbc.Driver"/> <property name="jdbcUrl" value="jdbc:mysql:///spring_04"/> <property name="user" value="root"/> <property name="password" value="root"/> </bean> <!-- 配置JdbcTemplate模板 --> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 配置平台事務管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 開啟事務註解 --> <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven> </beans> Service層用註解 : //實現類 @Service("accountService") @Transactional(isolation=Isolation.DEFAULT) public class AccountServiceImpl implements AccountService { @Resource(name="accountDao") private AccountDao accountDao; // public void setAccountDao(AccountDao accountDao) { // this.accountDao = accountDao; // } //支付的方法 @Override public void pay(String out, String in, double money) { //模擬兩個操作 //減錢 accountDao.outMoney(out, money); //模擬異常 //int i = 10/0; accountDao.inMoney(in, money); } } 使用純註解的方式進行Spring事務管理 : /* * 配置類,Spring聲明式事務管理,純註解的方式 * */ @Configuration @ComponentScan(basePackages="com.baidu.demo5") @EnableTransactionManagement //純註解的方式,開啟事務註解 public class SpringConfig { @Bean(name="dataSource") public DataSource createDataSource() throws Exception{ ComboPooledDataSource dataSource = new ComboPooledDataSource(); dataSource.setDriverClass("com.mysql.jdbc.Driver"); dataSource.setJdbcUrl("jdbc:mysql:///spring_04"); dataSource.setUser("root"); dataSource.setPassword("root"); return dataSource; } //把dataSource注入進來 @Bean(name="jdbcTemplate") @Resource(name="dataSource") public JdbcTemplate createJdbcTemplate(DataSource dataSource) { return new JdbcTemplate(dataSource); } //創建平台事務管理器對象 @Bean(name="transactionManager") @Resource(name="dataSource") public PlatformTransactionManager createTransactionManager(DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } } 1 : 傳播行為 : 解決業務層方法之間互相調用的問題. 傳播行為的默認值 : 保證save和update方法在同一個事務中. 2 : Spring事務管理 : (1) : XML配置文件 ; (2) : XML+註解配置文件 ; (3) : 純註解 Spring框架提供了介面和實現類,進行事務管理的. PlatformTransactionManager介面 : 平台事務管理器,提供和回滾事務的. HibernateTransactionManager : hibernate框架事務管理的實現類. DataSourceTransactionManager : 使用JDBC或者MyBattis框架 TransactionDefinition介面 : 事務的定義的資訊.提供很多常量,分別表示隔離級別,傳播行為. 傳播行為 : 事務的傳播行為,解決service方法之間的調用的問題. Spring聲明式事務管理,使用AOP技術進行事務管理. 通知/增強 : 事務管理的方法,不用咋們自己編寫.需要配置. 連接池 DataSource ,存在Connection ,使用JDBC進行事務管理 ,conn.commit() | |注入 平台事務管理器(必須配置的),是Spring提供介面,提交和回滾事務 | |注入 自己編寫通知方法(事務管理),Spring提供通知,配置通知 | |注入 配置AOP增強 aop:config
