Spring事务管理的两种方式

目前项目开发过程中对于Spring的事务管理,主要就这么两种方式:XML配置方式和注解方式

在平时开发中,Spring团队建议使用注解的方式进行配置,这样配置文件显得精简,同时也会做到精确控制

 

注解方式

必须包



 User.java

package com.javacrazyer.spring.bean;

public class User
{
	private int id;
	private String username;
	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;
	}
}

 这个user在mysql中肯定是要创建的

create table users
(                   
 id int(11) not null auto_increment,  
 username varchar(20) not null,       
 primary key (id)                   
) 

 

    UserDAO.java类

package com.javacrazyer.spring.dao;

import java.util.List;

import com.javacrazyer.spring.bean.User;

public interface UserDAO
{
	public void save(User user);
	public void update(User user);
	public User getUser(int id);
	public void delete(int id);
	public List<User> getAllUsers();
}

  UserRowMapper类

package com.javacrazyer.spring.dao.impl;

import java.sql.ResultSet;
import java.sql.SQLException;

import org.springframework.jdbc.core.RowMapper;

import com.javacrazyer.spring.bean.User;

public class UserRowMapper implements RowMapper {

	public Object mapRow(ResultSet rs, int index) throws SQLException {
		User user = new User();
		user.setUsername(rs.getString("username"));
		user.setId(rs.getInt("id"));
		return user;
	}
}

 

UserDAOImpl.java具体实现类

package com.javacrazyer.spring.dao.impl;

import java.util.List;

import javax.sql.DataSource;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.javacrazyer.spring.bean.User;
import com.javacrazyer.spring.dao.UserDAO;


@Transactional
public class UserDAOImpl implements UserDAO
{
	//private DataSource dataSource;
	private JdbcTemplate jdbcTemplate;
	public void setDataSource(DataSource dataSource)
	{
		//this.dataSource = dataSource;
		this.jdbcTemplate=new JdbcTemplate(dataSource);
	}

	public void delete(int id)
	{
		jdbcTemplate.update("delete from users where id=?", new Object[]{id},
				new int[]{java.sql.Types.INTEGER});
		//jdbcTemplate.update("delete from users1 where id=10");
	}

	public List<User> getAllUsers()
	{
		return (List<User>)jdbcTemplate.query("select * from users", new UserRowMapper());
	}
	
	@Transactional(propagation=Propagation.NOT_SUPPORTED)  
	public User getUser(int id)
	{
		return (User)jdbcTemplate.queryForObject("select * from users where id=?", new Object[]{id}, 
				new int[]{java.sql.Types.INTEGER}, new UserRowMapper());

	}

	public void save(User user)
	{ 
		jdbcTemplate.update("insert into users(username) values(?)", new Object[]{user.getUsername()},
				new int[]{java.sql.Types.VARCHAR});

	}

	public void update(User user)
	{
		jdbcTemplate.update("update users set username=? where id=?", new Object[]{user.getUsername(),user.getId()},
				new int[]{java.sql.Types.VARCHAR, java.sql.Types.INTEGER});

	}

}

 

最后的测试类

package com.javacrazyer.spring.test;

import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.transaction.annotation.Transactional;

import com.javacrazyer.spring.bean.User;
import com.javacrazyer.spring.dao.UserDAO;


@Transactional
public class UserDAOImplTest
{
	UserDAO userDAO;
	
	@Before
	public void init()
	{
		try {
			ApplicationContext cxt = new ClassPathXmlApplicationContext("applicationContext.xml");
			userDAO= (UserDAO) cxt.getBean("userDAO");
		} catch (RuntimeException e) {
			e.printStackTrace();
		}

	}
	@Test
	public void testDelete()
	{
		userDAO.delete(11);
	}

	@Test
	public void testGetAllUsers()
	{
		for(User user : userDAO.getAllUsers()){
			System.out.println(user.getUsername());
		}

	}

	@Test
	public void testGetUser()
	{
		User user = userDAO.getUser(1);
		System.out.println(user.getUsername());

	}

	@Test
	public void testSave()
	{
		for(int i=0; i<5; i++)
		{
			User user=new User();
			user.setUsername("coolszy"+i);
			userDAO.save(user);
		}
	}

	@Test
	public void testUpdate()
	{
		User user=userDAO.getUser(1);
		user.setUsername("kuka");
		userDAO.update(user);

	}

}

   Spring的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-2.5.xsd
				http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
				http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
				http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<!--这里占位符配置可以配置在一个占位符类bean,也可以全局配置一句话就行	-->
	<context:property-placeholder location="classpath:jdbc.properties" />
<!--	<bean id="propertyConfigurer"-->
<!--		class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">-->
<!--		<property name="location" value="/WEB-INF/jdbc.properties" />-->
<!--	</bean>-->

	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
		destroy-method="close">
		<property name="driverClassName" value="${driverClassName}" />
		<property name="url" value="${url}" />
		<property name="username" value="${username}" />
		<property name="password" value="${password}" />
		<!-- 连接池启动时的初始值 -->
		<property name="initialSize" value="${initialSize}" />
		<!-- 连接池的最大值 -->
		<property name="maxActive" value="${maxActive}" />
		<!-- 最大空闲值.当经过一个高峰时间后,连接池可以慢慢将已经用不到的连接慢慢释放一部分,一直减少到maxIdle为止 -->
		<property name="maxIdle" value="${maxIdle}" />
		<!--  最小空闲值.当空闲的连接数少于阀值时,连接池就会预申请去一些连接,以免洪峰来时来不及申请 -->
		<property name="minIdle" value="${minIdle}" />
	</bean>
	
     <!--spring事务管理器	-->
	<bean id="txManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<!-- 指定数据源 -->
		<property name="dataSource" ref="dataSource" />
	</bean>
     <!--开启对注解的支持	-->
	<tx:annotation-driven transaction-manager="txManager" />

	<bean id="userDAO" class="com.szy.spring.dao.impl.UserDAOImpl">
		<property name="dataSource" ref="dataSource" />
	</bean>
</beans>

 jdbc.properties

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/test
username=root
password=root
initialSize=1
maxActive=100
maxIdle=2
minIdle=1

在注解方式编写测试代码,代码运行正常。

在我们实现的每个方法中如delete()方法,如果delete方法是这样

public void delete(int id)
	{
		jdbcTemplate.update("delete from users where id=?", new Object[]{id},
				new int[]{java.sql.Types.INTEGER});
jdbcTemplate.update("delete from users where id=?", new Object[]{id},
				new int[]{java.sql.Types.INTEGER});

	}
	

 

 这样每条语句都会在各自的事务中执行,并不能保证在同一使用中执行,为了保证在同一事务中执行,我们应使用Spring容器提供的声明事务,我们在UserDAOImpl 类上加入@Transactional,表示该类受Spring事务管理。如果该类中每个方法不需要事务管理,如getUser方法,则在该方法前加入

@Transactional(propagation=Propagation.NOT_SUPPORTED)

  

XML配置方式

 必须包



 这里就UserDAOImpl.java,applicationContext.xml与上边不同

 UserDAOImpl.java就是去掉了所有@Transactional的注解

 applictionContext.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-2.5.xsd
				http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
				http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
				http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
		<context:property-placeholder location="classpath:jdbc.properties"/>
		<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
		    <property name="driverClassName" value="${driverClassName}"/>
		    <property name="url" value="${url}"/>
		    <property name="username" value="${username}"/>
		    <property name="password" value="${password}"/>
			<!-- 连接池启动时的初始值 -->
			<property name="initialSize" value="${initialSize}"/>
			<!-- 连接池的最大值 -->
			<property name="maxActive" value="${maxActive}"/>
			<!-- 最大空闲值.当经过一个高峰时间后,连接池可以慢慢将已经用不到的连接慢慢释放一部分,一直减少到maxIdle为止 -->
			<property name="maxIdle" value="${maxIdle}"/>
			<!--  最小空闲值.当空闲的连接数少于阀值时,连接池就会预申请去一些连接,以免洪峰来时来不及申请 -->
			<property name="minIdle" value="${minIdle}"/>
	 	</bean>
	 	
	 	<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  	   		<!-- 指定数据源 -->
  	   		<property name="dataSource" ref="dataSource"/>
    	</bean>
    	
		<aop:config>
		 	<aop:pointcut id="transactionPointcut" expression="execution(* com.szy.spring.dao.impl..*.*(..))"/>
		 	<aop:advisor advice-ref="txAdvice" pointcut-ref="transactionPointcut"/>
		</aop:config> 
		<tx:advice id="txAdvice" transaction-manager="txManager">
			  <tx:attributes>
			  	<!-- 如果方法是以get开头,能不进行事务管理 -->
			    <tx:method name="get*" read-only="true" propagation="NOT_SUPPORTED"/>
			    <tx:method name="*"/>
			  </tx:attributes>
		</tx:advice>
		
		
		<bean id="userDAO" class="com.szy.spring.dao.impl.UserDAOImpl">
			<property name="dataSource" ref="dataSource"/>
		</bean>
</beans>

 

这里没有了注解支持,而是配成了tx标签开头的声明式事务管理方式,基于aspectJ的配置

 

下面我们测试下数据库操作是否在同一事务中执行。

假设我们的delete方法如下:

public void delete(int id)
 {
  jdbcTemplate.update("delete from users where id=?", new Object[]{id},
    new int[]{java.sql.Types.INTEGER});
  jdbcTemplate.update("delete from users1 where id=10");
 }

 

在第二条删除语句中,users1表是不存在的,如果两次update语句是在两个事务中执行,则第一条能成功执行,并且数据库中该id的记录已经被删除,而第二条由于不存在该表不能正常删除。如果在同一事务中执行,由于第二条update出错,数据库中不能删除任何记录。

   测试代码

@Test
 public void testDelete()
 {
  userDAO.delete(5);
 }

 

程序报错,同时id=5的记录没有被删除。如果我们把配置文件中关于事务配置的信息给注释掉,再次测试,程序同样报错,但是id=5的记录被成功删除掉,这说明这两条update语句是在两个不同的事务中运行。

    所以配置事务就是保证,无论方法中有多少条更新语句,那么我只要保证整个方法在同一个事务中执行就OK

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值