1、聲明式事務
2、Spring事務引入的分析------PlatformTransactionManager類簡單介紹
3、注解式事務聲明
4、xml配置式事務聲明
5、Spring整合Web
1、聲明式事務
事務分為聲明式和程式設計式兩種:
聲明式事務:聲明式事務是指通過注解的形式對事務的各種特性進行控制和管理。
編碼式(程式設計式)事務:指的是通過編碼的方式實作事務的聲明。
1.1、編碼方式實作事務:
1.2、聲明式事務環境搭建
1.2.2、準備測試資料庫
##建立tx資料庫
drop database if exists `tx`;
CREATE database `tx`;
##切換tx資料庫
USE `tx`;
##删除使用者表
DROP TABLE IF EXISTS `user`;
##建立使用者表
CREATE TABLE `user` (
`id` int primary key auto_increment,
`username` varchar(50) NOT NULL,
`money` int(11) DEFAULT NULL
);
##插入資料
insert into `user`(`username`,`money`) values ('張三',1000),('李四',1000);
##删除圖書表
drop table if exists `book`;
##建立圖書表
create table `book`(
`id` int primary key auto_increment,
`name` varchar(500) not null,
`stock` int
);
##插入資料
insert into book(`name`,`stock`) values('java程式設計思想',100),('C++程式設計思想',100);
##檢視資料
select * from book;
select * from user;
1.2.2、建立一個Java工程,導入Jar包
JavaBean對象
public class Book {
private Integer id;
private String name;
private int stock;
public class User {
private Integer id;
private String username;
private int money;
Dao們
@Repository
public class BookDao {
@Autowired
private JdbcTemplate jdbcTemplate;
public int updateBook() {
String sql = "update book set name = '**我被修改了!**' where id = 1";
return jdbcTemplate.update(sql);
}
}
@Repository
public class UserDao {
@Autowired
private JdbcTemplate jdbcTemplate;
public int updateUser() {
String sql = "update user set username = '**我被修改了**' where id = 1";
return jdbcTemplate.update(sql);
}
}
Service代碼
@Service
public class TransactionService {
@Autowired
private UserDao userDao;
@Autowired
private BookDao bookDao;
public void updateTwoTable() {
userDao.updateUser();
bookDao.updateBook();
}
}
1.3、測試Service的預設事務
實驗1:測試service服務層的預設事務
@ContextConfiguration(locations = "classpath:application.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class SpringTest {
@Autowired
private DataSource dataSource;
@Autowired
private JdbcTemplate jdbcTemplate;
@Autowired
private TransactionService transactionService;
@Test
public void testDataSource() throws Exception {
System.out.println(dataSource.getConnection());
}
@Test
public void testJdbcTempalte() throws Exception {
System.out.println( jdbcTemplate );
}
@Test
public void testTransaction() throws Exception {
transactionService.updateTwoTable();
}
}
異常的示範
public void updateTwoTable() {
userDao.updateUser();
int i = 12 / 0;
bookDao.updateBook();
}
結果:
但結果卻是一張表更新了,另一種表未更新就發生異常,導緻兩張表不能同步,經典案例就是銀行的轉賬,這邊轉過去了,對方沒有收到。這裡就要用到事務來處理了,要是在同一個事務中有一處出錯,整個事務都復原,進而阻止這種非一緻性的更新操作。
2、Spring事務引入的分析------PlatformTransactionManager類簡單介紹
PlatformTransactionManager接口,提供所有事務操作規範。我們使用DataSource資料庫連接配接池,使用的事務管理器是DataSourceTransactionManager類
注:和Javaweb的Filter、jdk動态代理、aop、Utilsjdbc的原理一樣分三層結構處理業務
3、注解式事務聲明
3.1使用Spring的注解式聲明事務管制
實驗2:測試Spring的聲明式事務
先導入AOP包,因為Spring的底層事務使用到了aop功能
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
spring-aop-4.0.0.RELEASE.jar
spring-aspects-4.0.0.RELEASE.jar
配置Spring的事務需要的切面類DataSourceTransactionManager
<!-- 配置DataSourceTransactionManager事務管理器===事務的切面類 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
在Spring的配置檔案中加入tx名稱空間
在Spring的配置檔案中
<!-- 配置啟用spring的事務注解驅動@Transactional -->
<tx:annotation-driven transaction-manager="transactionManager"/>
還需要在Service的事務方法中添加@Transactioaln注解
@Transactional
public void updateTwoTable() {
userDao.updateUser();
int i = 12 / 0;
bookDao.updateBook();
}
3.2、noRollbackFor和noRollbackForClassName測試不復原的異常
實驗3:noRollbackFor和noRollbackForClassName測試不復原的異常
/**
* noRollbackFor=ArithmeticException.class 表示當接收到數學異常之後。不復原<br/>
* noRollbackForClassName="java.lang.ArithmeticException" 表示當接收到指定字元串表示的全類名的異常的時候,不復原事務
*/
@Transactional(noRollbackFor=ArithmeticException.class)
public void updateTwoTable() {
userDao.updateUser();
int i = 12 / 0;
bookDao.updateBook();
}
Book:
User表:
注:spring預設復原的是運作時異常RuntimeException和RuntimeException的子異常
3.3、自定義設定復原異常
實驗5:rollbackFor和rollbackForClassName復原的異常
Spring預設復原的是RuntimeException,運作時異常或運作時異常的子異常
/**
* spring預設復原的是運作時異常RuntimeException和RuntimeException的子異常<br/>
* rollbackFor=FileNotFoundException.class 表示FileNotFoundException也會復原
* rollbackForClassName="java.io.FileNotFoundException" 表示當出現配置字元串所表示的全類名的異常的時候。也會復原事務
* @throws FileNotFoundException
*
*/
@Transactional(rollbackFor=FileNotFoundException.class)
public void updateTwoTable() throws FileNotFoundException {
userDao.updateUser();
int i = 0;
if (i == 0) {//java.io.FileNotFoundException
throw new FileNotFoundException("sadf");
}
bookDao.updateBook();
}
3.3、事務的隻讀屬性
實驗4:測試readOnly隻讀屬性
/**
* readOnly 如果值為true。表示隻支援查詢操作。不支援寫操作
* <br/>如果設定為false,支援全部
*/
@Transactional(readOnly=true)
public void updateTwoTable() throws FileNotFoundException {
userDao.updateUser();
bookDao.updateBook();
}
3.4、事務逾時屬性timeout(秒為機關)
timeout=3表示操作不能超過3秒,否在就包錯
@Transactional(timeout=3)
public void updateTwoTable() throws FileNotFoundException {
userDao.updateUser();
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
bookDao.updateBook();
}
3.5、事務的傳播特性propagation
什麼是事務的傳播行為:
當事務方法(XxxService())被另一個事務方法調用時,必須指定事務應該如何傳播。例如:方法可能繼續在現有事務中運作,也可能開啟一個新事務,并在自己的事務中運作。
事務的傳播行為可以由傳播屬性指定。Spring定義了7種類傳播行為。
事務的傳播特性,有以下幾種類型:(常用的就前兩種,是以下面進行這兩種的測試)required(預設的)
3.6、注解示範事物傳播特性
因為事務方法是被其他事務方法調用是以,添加幾個事務方法進行測試
UserService
BookService
TransactionService
實驗1:大小事務傳播特性都是REQUIRED、
實驗2:大小事務傳播特性都是REQUIRES_NEW
實驗3:大事務是REQUIRED,小事務都是REQUIRES_NEW
實驗4:大事務是REQUIRED,小1REQUIRED,小2REQUIRES_NEW
實驗5:大事務是REQUIRED,小1REQUIRES_NEW,小2REQUIRED
實驗1:大小事務傳播特性都是REQUIRED
@Transactional(propagation = Propagation.REQUIRED)
public void multiUpdate() {
@Transactional(propagation = Propagation.REQUIRED)
public void updateBook() {
@Transactional(propagation=Propagation.REQUIRED)
public void updateUser() {
實驗2:大小事務傳播特性都是REQUIRES_NEW
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void multiUpdate()
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateBook()
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateUser()
實驗3:大事務是REQUIRED,小事務都是REQUIRES_NEW
@Transactional(propagation = Propagation.REQUIRED)
public void multiUpdate()
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateBook()
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateUser()
實驗4:大事務是REQUIRED,小1REQUIRED,小2REQUIRES_NEW
@Transactional(propagation = Propagation.REQUIRED)
public void multiUpdate()
@Transactional(propagation = Propagation.REQUIRED)
public void updateBook()
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateUser()
實驗5:大事務是REQUIRED,小1REQUIRES_NEW,小2REQUIRED
@Transactional(propagation = Propagation.REQUIRED)
public void multiUpdate()
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateBook()
@Transactional(propagation = Propagation.REQUIRED)
public void updateUser()
4、xml配置式事務聲明
去掉。所有@Transactional的注解。
當然注解有的功能,xml也可以實作
<!-- 配置DataSourceTransactionManager事務管理器===事務的切面類 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 事務特性 -->
<tx:advice id="tx_advice" transaction-manager="transactionManager">
<!-- 配置事務特性 -->
<tx:attributes>
<tx:method name="multiUpdate" propagation="REQUIRED"/>
<tx:method name="updateBook" propagation="REQUIRES_NEW" />
<tx:method name="updateUser" propagation="REQUIRED"/>
<tx:method name="*" read-only="true"/>
</tx:attributes>
</tx:advice>
<!-- 配置aop代理,一定要有切入點表達式 -->
<aop:config>
<aop:advisor advice-ref="tx_advice" pointcut="execution(* com.atguigu.service.*Service.*(..))" />
</aop:config>
總結:使用jdbcTemplate或者是事務管理器 屬性都要引用資料源,因為都是在資料庫連接配接的基礎上操作的。
總結:注解方式和配置檔案方式的事務
(1)、無論哪種方式,預設都是propagation="REQUIRED";方式
(2)、無論哪種方式,預設值都是:transaction-manager="transactionManager"
(3)、無論哪種方式,都要有事務管理器---管理事務的切面類-DataSourceTransactionManager
advice - advisor :建議 ,顧問
配置檔案情況下:一、(為什麼用aop.jar包?因為事務的底層是用aop的三層結構實作的,學習aop的主要作用就是處理事務)
<!-- 配置aop代理 -->
<aop:config>
<aop:advisor advice-ref="tx_advice" pointcut="execution(* com.atguigu.service.*Service.*(..))" />
</aop:config>
二、還有事務的特性配置
注解方法情況下:在Spring的配置檔案中
<!-- 配置 啟用spring的事務(tx:) 注解(annotation) 驅動(driven )@Transactional -->
<tx:annotation-driven transaction-manager="transactionManager"/>
這裡的transaction-manager="transactionManager"一般如果切面類的id值是transactionManager,這裡就可以省略了,陰謀在事務的注解驅動裡,預設是這個值的。但如果切面類的管理器的id不是這個值,這裡就一定要加上對應的值了。
5、Spring整合Web
5.1在web工程中添加Spring的jar包。
Spring的核心包
spring-beans-4.0.0.RELEASE.jar
spring-context-4.0.0.RELEASE.jar
spring-core-4.0.0.RELEASE.jar
spring-expression-4.0.0.RELEASE.jar
aop包
spring-aop-4.0.0.RELEASE.jar(注解,包掃描)
spring-aspects-4.0.0.RELEASE.jar
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
JDBC-ORM包
spring-jdbc-4.0.0.RELEASE.jar
spring-orm-4.0.0.RELEASE.jar
spring-tx-4.0.0.RELEASE.jar(事務管理)
Spring的web整合包
spring-web-4.0.0.RELEASE.jar
測試包
spring-test-4.0.0.RELEASE.jar
整合Spring和Web容器分兩個步驟:
1、導入spring-web-4.0.0.RELEASE.jar
2、在web.xml配置檔案中配置org.springframework.web.context.ContextLoaderListener(直接提示導入,無需記憶)監聽器監聽ServletContext的初始化
3、在web.xml配置檔案中配置contextConfigLocation上下文參數。配置Spring配置檔案的位置,以用于初始化Spring容器
5.2在web.xml中配置
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
5.3擷取WebApplicationContext上下文對象的方法如下:
方法一(官方推薦):
WebApplicationContextUtils.getWebApplicationContext(getServletContext())
方法二(不推薦):
getServletContext().getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
Spring詳解三之AOP與資料通路
常用spring開發jar包即額外包下載下傳