1. 程式人生 > >Spring 事務 (xml配置aop、註解事務)

Spring 事務 (xml配置aop、註解事務)

1.spring事務是基於aop思想實現的,即aop事務

  • spring封裝了事務管理程式碼
  • 事務操作:開啟事務,提交事務,回滾事務
  • 事務操作物件:因為在不同平臺,操作事務的程式碼各不相同.spring提供了一個介面,PlatformTransactionManager 介面
  1. DataSourceTransactionManager
  2. HibernateTransitionmanager
  3. 注意:在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