Spring之事務管理
事務管理
事務的認識
資料庫事務,是指作為單個工作單元執行的一系列操作,要麼完全地執行,要麼完全地不執行。事務管理可以確保除非事務性單元內地所有操作都成功完成,否則不會永久更新面向資料地資源。
事務具備ACID四種特性,ACID是Atomic(原子性)、Consistency(一致性)、Isolation(隔離性)和Durability(永續性)的英文縮寫。
①、原子性(Atomicity):事務是一個原子操作,由一系列動作組成。事務的原子性確保動作要麼全部完成,要麼完全不起作用。
②、一致性(Consistency):一旦事務完成(不管成功還是失敗),系統必須確保它所建模的業務處於一致的狀態,而不會是部分完成部分失敗。在現實中的資料不應該被破壞。
③、隔離性(Isolation):可能有許多事務會同時處理相同的資料,因此每個事務都應該與其他事務隔離開來,防止資料損壞。
④、永續性(Durability):一旦事務完成,無論發生什麼系統錯誤,它的結果都不應該受到影響,這樣就能從任何系統崩潰中恢復過來。通常情況下,事務的結果被寫到持久化儲存器中。
事務的隔離級別
(1)read uncommited:是最低的事務隔離級別,它允許另外一個事務可以看到這個事務未提交的資料。 (2)read commited:保證一個事物提交後才能被另外一個事務讀取。另外一個事務不能讀取該事物未提交的資料。 (3)repeatable read:這種事務隔離級別可以防止髒讀,不可重複讀。但是可能會出現幻象讀。它除了保證一個事務不能被另外一個事務讀取未提交的資料之外還避免了以下情況產生(不可重複讀)。 (4)serializable:這是花費最高代價但最可靠的事務隔離級別。事務被處理為順序執行。除了防止髒讀,不可重複讀之外,還避免了幻象讀 (5)髒讀、不可重複讀、幻象讀概念說明: a.髒讀:指當一個事務正字訪問資料,並且對資料進行了修改,而這種資料還沒有提交到資料庫中,這時,另外一個事務也訪問這個資料,然後使用了這個資料。因為這個資料還沒有提交那麼另外一個事務讀取到的這個資料我們稱之為髒資料。依據髒資料所做的操作肯能是不正確的。 b.不可重複讀:指在一個事務內,多次讀同一資料。在這個事務還沒有執行結束,另外一個事務也訪問該同一資料,那麼在第一個事務中的兩次讀取資料之間,由於第二個事務的修改第一個事務兩次讀到的資料可能是不一樣的,這樣就發生了在一個事物內兩次連續讀到的資料是不一樣的,這種情況被稱為是不可重複讀。 c.幻象讀:一個事務先後讀取一個範圍的記錄,但兩次讀取的紀錄數不同,我們稱之為幻象讀(兩次執行同一條 select 語句會出現不同的結果,第二次讀會增加一資料行,並沒有說這兩次執行是在同一個事務中)
案例演示(為了方便使用註解)
bean層
package com.sxt.bean; public class User { private int id; private String username; private String password; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "User [id=" + id + ", username=" + username + ", password=" + password + "]"; } }
Dao層及其實現類
package com.sxt.dao;
public interface UserDao {
public void add();
public void update();
public void delete();
public void query();
}
package com.sxt.dao.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.ResultSetExtractor;
import org.springframework.stereotype.Repository;
import com.sxt.bean.User;
import com.sxt.dao.UserDao;
@Repository
public class UserDaoImpl implements UserDao {
@Autowired
private JdbcTemplate template;
@Override
public void add() {
String sql = "insert t_user(username,password)values(?,?)";
int i = template.update(sql,"aa","11");
System.out.println("影響一行"+i);
}
@Override
public void update() {
String sql = "update t_user set username=?,password=? where id=?";
int i = template.update(sql,"bb","22",2);
System.out.println("影響一行"+i);
}
@Override
public void delete() {
String sql = "delete from t_user where id=?";
int i = template.update(sql,2);
System.out.println("影響一行"+i);
}
@Override
public void query() {
String sql = "select * from t_user";
List<User> query = template.query(sql, new BeanPropertyRowMapper<User>(User.class));
for (User user : query) {
System.out.println(user);
}
}
}
Service層及其實現類
package com.sxt.service;
public interface UserService {
public void fun();
}
package com.sxt.service.impl;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
import com.sxt.dao.UserDao;
import com.sxt.service.UserService;
@Service
public class UserServiceImpl implements UserService{
@Resource
private UserDao dao;
@Override
public void fun() {
dao.add();
dao.delete();
dao.update();
dao.query();
}
}
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-4.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
<!-- 開啟註解 -->
<context:component-scan base-package="com.sxt.*"></context:component-scan>
<bean class="org.springframework.jdbc.datasource.DriverManagerDataSource" id="dataSource">
<!-- 設定注入 -->
<property name="driverClassName" value="com.mysql.jdbc.Driver "/>
<property name="url" value="jdbc:mysql://localhost:3306/pms?characterEncoding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
<bean class="org.springframework.jdbc.core.JdbcTemplate" id="jdbcTemplate">
<constructor-arg ref="dataSource"/>
</bean>
<!-- 配置事務管理 -->
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="dataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置事務方法 -->
<tx:advice id="tx" transaction-manager="dataSourceTransactionManager">
<tx:attributes>
<tx:method name="fun*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!-- 配置AOP -->
<aop:config>
<aop:pointcut expression="execution(* com.sxt.service.impl.*.*(..))" id="aop"/>
<aop:advisor advice-ref="tx" pointcut-ref="aop"/>
</aop:config>
</beans>
測試呼叫
package com.sxt;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.sxt.service.UserService;
/**
* 測試
* @author Administrator
*
*/
public class Test {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("application.xml");
UserService bean = ac.getBean(UserService.class);
bean.fun();
}
}
在Dao層實現類給出程式碼錯誤程式碼
在測試執行
雖然結果顯示影響一行但是資料庫並沒有新增刪除,修改資料,事務管理保證了對這一系列的資料庫增刪查改要麼同時成功,要麼同時失敗
使用註解方式
Dao層及其實現類和service層程式碼一樣引用上面的
配置檔案
<?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-4.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
<!-- 開啟註解 -->
<context:component-scan base-package="com.sxt.*"></context:component-scan>
<bean class="org.springframework.jdbc.datasource.DriverManagerDataSource" id="dataSource">
<!-- 設定注入 -->
<property name="driverClassName" value="com.mysql.jdbc.Driver "/>
<property name="url" value="jdbc:mysql://localhost:3306/pms?characterEncoding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
<bean class="org.springframework.jdbc.core.JdbcTemplate" id="jdbcTemplate">
<constructor-arg ref="dataSource"/>
</bean>
<!-- 配置事務管理 -->
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="dataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 開啟註解地方式 -->
<tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>
</beans>
service實現類
package com.sxt.service.impl;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.sxt.dao.UserDao;
import com.sxt.service.UserService;
@Service
public class UserServiceImpl implements UserService{
@Resource
private UserDao dao;
@Transactional
@Override
public void fun() {
dao.add();
dao.delete();
dao.update();
dao.query();
}
}
測試
package com.sxt;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.sxt.service.UserService;
public class Test {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("application.xml");
UserService bean = ac.getBean(UserService.class);
bean.fun();
}
}