Spring 事務 (xml配置aop、註解事務)
阿新 • • 發佈:2019-01-10
1.spring事務是基於aop思想實現的,即aop事務
- spring封裝了事務管理程式碼
- 事務操作:開啟事務,提交事務,回滾事務
- 事務操作物件:因為在不同平臺,操作事務的程式碼各不相同.spring提供了一個介面,PlatformTransactionManager 介面
- DataSourceTransactionManager
- HibernateTransitionmanager
- 注意:在spring事務管理.最為核心的物件就是TransactionManager物件
- spring管理事務的屬性介紹
1.事務得隔離級別:
1 讀未提交
2 讀已提交
4 可重複讀
8 序列化2,是否只讀
true 只讀
false 可操作3,事務的傳播行為
2.xml實現aop事務
(需要先了解spring aop面向切面程式設計)
1.在spring配置檔案中配置通知:
<!--在spring中玩事務管理.最為核心的物件就是TransactionManager物件 --> <!-- 配置事務管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!-- 配置事物通知 --> <tx:advice id="transactionAdvice" transaction-manager="transactionManager"> <tx:attributes> <!--以方法為單位,指定方法應用什麼事務屬性 --> <!--isolation隔離級別 propagation傳播行為 read-only是否只讀 --> <tx:method name="add*" isolation="DEFAULT" propagation="REQUIRED" read-only="false" /> <tx:method name="append*" isolation="DEFAULT" propagation="REQUIRED" read-only="false"/> <tx:method name="insert*" isolation="DEFAULT" propagation="REQUIRED" read-only="false" /> <tx:method name="save*" isolation="DEFAULT" propagation="REQUIRED" read-only="false" /> <tx:method name="update*" isolation="DEFAULT" propagation="REQUIRED" read-only="false" /> <tx:method name="modify*" isolation="DEFAULT" propagation="REQUIRED" read-only="false" /> <tx:method name="edit*" isolation="DEFAULT" propagation="REQUIRED" read-only="false"/> <tx:method name="delete*" isolation="DEFAULT" propagation="REQUIRED" read-only="false" /> <tx:method name="remove*" isolation="DEFAULT" propagation="REQUIRED" read-only="false" /> <tx:method name="repair" isolation="DEFAULT" propagation="REQUIRED" read-only="false" /> <tx:method name="delAndRepair" isolation="DEFAULT" propagation="REQUIRED" read-only="false" /> <tx:method name="get*" isolation="DEFAULT" propagation="REQUIRED" read-only="true" /> <tx:method name="find*" isolation="DEFAULT" propagation="REQUIRED" read-only="true" /> <tx:method name="load*" isolation="DEFAULT" propagation="REQUIRED" read-only="true" /> <tx:method name="search*" isolation="DEFAULT" propagation="REQUIRED" read-only="true" /> <tx:method name="datagrid*" isolation="DEFAULT" propagation="REQUIRED" read-only="true" /> </tx:attributes> </tx:advice>
2.配置將通知織入目標
<!-- 配置織入 --> <aop:config> <!-- 將service層需要事務的方法作為切點 --> <aop:pointcut id="transactionPointcut" expression="execution(* com.sj.service.imp.*DerviceImp.*(..))" /> <!--配置切面 通知+切點--> <aop:advisor pointcut-ref="transactionPointcut" advice-ref="transactionAdvice" /> </aop:config>
3.書寫dao以及實現dao
public interface UserDao {
void save(User u);
void delete(Integer id);
void update(User u);
User getUser(Integer id);
List<User> getAllUser();
void updateAddMoney(Integer id,Double money);
void updatereduceMoney(Integer id,Double money);
}
public class UserDaoImp extends JdbcDaoSupport implements UserDao {
@Override
public void save(User u) {
String sql = "insert into user (name,money) values(?,?)";
super.getJdbcTemplate().update(sql, u.getName(), u.getMoney());
}
@Override
public void delete(Integer id) {
String sql = "delete from user where id = ?";
super.getJdbcTemplate().update(sql, id);
}
@Override
public void update(User u) {
String sql = "update user set name = ? where id = ? ";
super.getJdbcTemplate().update(sql, u.getName(), u.getId());
}
@Override
public User getUser(Integer id) {
String sql = "select * from user where id = ?";
User u = super.getJdbcTemplate().queryForObject(sql, new RowMapper<User>() {
@Override
public User mapRow(ResultSet rs, int arg1) throws SQLException {
User u = new User();
u.setId(rs.getInt("id"));
u.setName(rs.getString("name"));
u.setMoney(rs.getDouble("money"));
return u;
}
}, id);
return u;
}
@Override
public List<User> getAllUser() {
String sql = "select * from user ";
List<User> u = super.getJdbcTemplate().query(sql, new RowMapper<User>() {
@Override
public User mapRow(ResultSet rs, int arg1) throws SQLException {
User u = new User();
u.setId(rs.getInt("id"));
u.setName(rs.getString("name"));
u.setMoney(rs.getDouble("money"));
return u;
}
});
return u;
}
@Override
public void updateAddMoney(Integer id, Double money) {
String sql = "update user set money=money + ? where id=?";
super.getJdbcTemplate().update(sql, money, id);
}
@Override
public void updatereduceMoney(Integer id, Double money) {
String sql = "update user set money=money - ? where id=?";
super.getJdbcTemplate().update(sql, money, id);
}
}
3.書寫service以及實現
public interface UserService {
void updateMoney(Integer from, Integer to, Double money);
void updateMoney2(Integer from, Integer to, Double money);
public User getUser(Integer id);
}
public class UserServiceImp implements UserService {
private UserDao userDao;
@Override
public User getUser(Integer id) {
User u = userDao.getUser(id);
return u;
}
// 轉錢
@Override
public void updateMoney(Integer from, Integer to, Double money) {
userDao.updatereduceMoney(from, money);
userDao.updateAddMoney(to, money);
}
// 轉錢 異常
@Override
public void updateMoney2(Integer from, Integer to, Double money) {
userDao.updatereduceMoney(from, money);
// 模擬異常
int s = 1;
int i = s / 0;
userDao.updateAddMoney(to, money);
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
4.注入dao,service到spring
<!-- 引入外部文檔案 -->
<context:property-placeholder location="classpath:db.properties"/>
<!--配置連線池 -->
<bean name="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!-- Dao -->
<bean name="userDao" class="com.sj.dao.imp.UserDaoImp">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- Service -->
<bean name="userService" class="com.sj.service.imp.UserServiceImp">
<property name="userDao" ref="userDao"></property>
</bean>
4.完整spirng配置檔案
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
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-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<!-- 引入外部文檔案 -->
<context:property-placeholder location="classpath:db.properties"/>
<!--配置連線池 -->
<bean name="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!-- Dao -->
<bean name="userDao" class="com.sj.dao.imp.UserDaoImp">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- Service -->
<bean name="userService" class="com.sj.service.imp.UserServiceImp">
<property name="userDao" ref="userDao"></property>
</bean>
<!--在spring中玩事務管理.最為核心的物件就是TransactionManager物件 -->
<!-- 配置事務管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 配置事物通知 -->
<tx:advice id="transactionAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!--以方法為單位,指定方法應用什麼事務屬性 -->
<!--isolation隔離級別 propagation傳播行為 read-only是否只讀 -->
<tx:method name="add*" isolation="DEFAULT" propagation="REQUIRED" read-only="false" />
<tx:method name="append*" isolation="DEFAULT" propagation="REQUIRED" read-only="false"/>
<tx:method name="insert*" isolation="DEFAULT" propagation="REQUIRED" read-only="false" />
<tx:method name="save*" isolation="DEFAULT" propagation="REQUIRED" read-only="false" />
<tx:method name="update*" isolation="DEFAULT" propagation="REQUIRED" read-only="false" />
<tx:method name="modify*" isolation="DEFAULT" propagation="REQUIRED" read-only="false" />
<tx:method name="edit*" isolation="DEFAULT" propagation="REQUIRED" read-only="false"/>
<tx:method name="delete*" isolation="DEFAULT" propagation="REQUIRED" read-only="false" />
<tx:method name="remove*" isolation="DEFAULT" propagation="REQUIRED" read-only="false" />
<tx:method name="repair" isolation="DEFAULT" propagation="REQUIRED" read-only="false" />
<tx:method name="delAndRepair" isolation="DEFAULT" propagation="REQUIRED" read-only="false" />
<tx:method name="get*" isolation="DEFAULT" propagation="REQUIRED" read-only="true" />
<tx:method name="find*" isolation="DEFAULT" propagation="REQUIRED" read-only="true" />
<tx:method name="load*" isolation="DEFAULT" propagation="REQUIRED" read-only="true" />
<tx:method name="search*" isolation="DEFAULT" propagation="REQUIRED" read-only="true" />
<tx:method name="datagrid*" isolation="DEFAULT" propagation="REQUIRED" read-only="true" />
</tx:attributes>
</tx:advice>
<!-- 配置織入 -->
<aop:config>
<!--配置切點 表示式 -->
<!-- 將service層需要事務的方法作為切點 -->
<aop:pointcut id="transactionPointcut" expression="execution(* com.sj.service.imp.*DerviceImp.*(..))" />
<!--配置切面 通知+切點-->
<aop:advisor pointcut-ref="transactionPointcut" advice-ref="transactionAdvice" />
</aop:config>
</beans>
5.Test測試
public class SpringTest {
@Test
public void run3() {
// 轉錢
ApplicationContext app = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
UserServiceImp service = (UserServiceImp) app.getBean("userService");
service.updateMoney(2, 1, 100d);
}
@Test
public void run4() {
// 轉錢(異常)
ApplicationContext app = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
UserServiceImp service = (UserServiceImp) app.getBean("userService");
service.updateMoney2(2, 1, 100d);
}
}
1.執行run3,轉賬成功
2.執行run4(執行應該轉賬失敗,回滾事務)
如果未配置事務結果是(執行減少自己賬戶前後出現異常,導致對方賬戶未收到)
配置事務後:
3.註解事務:就很簡單了直接新增
<tx:annotation-driven transaction-manager="transactionManager" />
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
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-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<!-- 引入外部文檔案 -->
<context:property-placeholder location="classpath:db.properties"/>
<!--配置連線池 -->
<bean name="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!-- Dao -->
<bean name="userDao" class="com.sj.dao.imp.UserDaoImp">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- Service -->
<bean name="userService" class="com.sj.service.imp.UserServiceImp">
<property name="userDao" ref="userDao"></property>
</bean>
<!--在spring中玩事務管理.最為核心的物件就是TransactionManager物件 -->
<!-- 配置事務管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 註解方式配置事物 -->
<tx:annotation-driven transaction-manager="transactionManager" />
</beans>
2.在service用註解實現事務
//類註解給所有方法新增事務,可以直接在方法覆蓋類註解事務
@Transactional(isolation = Isolation.REPEATABLE_READ, propagation = Propagation.REQUIRED, readOnly = true)
public class UserServiceImp implements UserService {
private UserDao userDao;
public User getUser(Integer id) {
User u = userDao.getUser(id);
return u;
}
// 轉錢,將只讀改為false
@Override
@Transactional(isolation = Isolation.REPEATABLE_READ, propagation = Propagation.REQUIRED, readOnly = false)
public void updateMoney(Integer from, Integer to, Double money) {
userDao.updatereduceMoney(from, money);
userDao.updateAddMoney(to, money);
}
// 轉錢 異常,將只讀改為false
@Override
@Transactional(isolation = Isolation.REPEATABLE_READ, propagation = Propagation.REQUIRED, readOnly = false)
public void updateMoney2(Integer from, Integer to, Double money) {
userDao.updatereduceMoney(from, money);
// 模擬異常
int s = 1;
int i = s / 0;
userDao.updateAddMoney(to, money);
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
註解事務就ok