spring事务管理使用总结

1.为什么使用事务管理

在应用中,对于任何数据处理的事务,都必须要保护数据的完整性。如果一个账户出现了丢失数据,譬如余额不准,交易金额丢失等,这种致命的错误必然导致用户的反感。而事务正式用来保证应用系统中数据的完整性。

2.事务遵守的原则

使用事务管理保证的几个原则:

我们常常应该在实现的系统中保证在不牺牲性能的原则下,保证ACID原则(原子性、一致性、隔离性、持久性)。

(1)原子性:在我们的事务中可能会出现很多的操作,可能出现操作成功和操作失败两种情况,原子性就是要保证如果操作成功就一定保持所有的操作都成功。如果失败就要保证所有的操作都失败。(术语:操作必须得回滚)。

(2)一致性:譬如我们在转账的时候,如果张三给李四转账,张三转了1000块,那么张三的账户少了1000元,那么李四的账户就必须要保证多了1000元。两边必须一致,也就是转账这个事务要保持一致性。

(3)隔离性:有时事务出现并发性时,要保证多个事务之间互不影响,就是一个事务的订单还未提交,另一个事务不会让订单提交了。两个事务隔离。发现其实隔离性和一致性是相关的。如果隔离性很好,那么一致性也很好。

(4)持久性:就是如果张三给李四转账1000元,如果张三已经转账成功,那么持久性就要保证数据不会丢失。不会因为其他修改而发生错误的改变。

3.XML方式实现spring的事务管理

搭建环境pom.xml:

<dependencies>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.9</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>4.0.0.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-beans</artifactId>
			<version>4.0.0.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>4.0.0.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-expression</artifactId>
			<version>4.0.0.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>commons-logging</groupId>
			<artifactId>commons-logging</artifactId>
			<version>1.1.3</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jdbc</artifactId>
			<version>4.0.0.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-tx</artifactId>
			<version>4.0.0.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>com.mchange</groupId>
			<artifactId>c3p0</artifactId>
			<version>0.9.2.1</version>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.38</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aop</artifactId>
			<version>4.0.0.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>aopalliance</groupId>
			<artifactId>aopalliance</artifactId>
			<version>1.0</version>
		</dependency>
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjrt</artifactId>
			<version>1.8.2</version>
		</dependency>
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjweaver</artifactId>
			<version>1.8.2</version>
		</dependency>
	</dependencies>
Model模型User.java:

public class User implements Serializable {
	private Integer id;
	private String username;
	private String gender;

	public User() {
		super();
		// TODO Auto-generated constructor stub
	}

	public User(Integer id, String username, String gender) {
		super();
		this.id = id;
		this.username = username;
		this.gender = gender;
	}

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getGender() {
		return gender;
	}

	public void setGender(String gender) {
		this.gender = gender;
	}

	@Override
	public String toString() {
		return "User [id=" + id + ", username=" + username + ", gender="
				+ gender + "]";
	}

}
dao层,UserDao.java:

public class UserDao {

	private JdbcTemplate jdbcTemplate;

	public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}

	public void save(User user) {
		String sql = "insert into myuser(id,username,gender) values(?,?,?)";
		jdbcTemplate.update(
				sql,
				new Object[] { user.getId(), user.getUsername(),
						user.getGender() }, new int[] { Types.INTEGER,
						Types.VARCHAR, Types.VARCHAR });
	}
}
service层,UserService.java:

public class UserService {

	private UserDao userDao;

	public void setUserDao(UserDao userDao) {
		this.userDao = userDao;
	}

	public void saveUser(User user) {
		userDao.save(user);
		int i = 1 / 0;
		userDao.save(user);
	}
}
解释:如果我们不使用事务控制就仍然会保存用户到数据库,如果我们加了事务控制就会因为异常的错误,让用户不会添加到数据库中。这样就保持了原子性。

配置文件bean.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:p="http://www.springframework.org/schema/p"
	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.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd">
	<!-- 1. 数据源对象: C3P0连接池 -->
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
		<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/basicjdbc?characterEncoding=utf-8"></property>
		<property name="user" value="root"></property>
		<property name="password" value=""></property>
		<property name="initialPoolSize" value="3"></property>
		<property name="maxPoolSize" value="10"></property>
		<property name="maxStatements" value="100"></property>
		<property name="acquireIncrement" value="2"></property>
	</bean>
	
	<!-- 配置jdbcTemplate工具类实例 -->
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	
	<!-- 配置Dao层 -->
	<bean id="userDao" class="cn.spy.transaction.xml.UserDao">
		<property name="jdbcTemplate" ref="jdbcTemplate"></property>
	</bean>
	
	<!-- 配置Service层 -->
	<bean id="userService" class="cn.spy.transaction.xml.UserService">
		<property name="userDao" ref="userDao"></property>
	</bean>
	
	<!-- 配置事务管理器类 -->
	<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	
	<!-- 配置事务增强 -->
	<tx:advice id="txAdvice" transaction-manager="txManager">
		<tx:attributes>
			<tx:method name="*saveUser*" read-only="false"/>
		</tx:attributes>
	</tx:advice>
	
	<!-- aop配置 -->
	<aop:config>
		<aop:pointcut expression="execution(* cn.spy.transaction.xml.UserService.*(..))" id="pt"/>
		<aop:advisor advice-ref="txAdvice" pointcut-ref="pt"/>
	</aop:config>
	
</beans>
解释:spring的事务管理,其实还是使用了spring的aop切面编程。(如果让我们去动手实现spring的事务管理的话,肯定是在哪个方法上面定义切点表达式进行监控,如果报出异常,那么我们就为了保持原子性,不进行回滚了。),所以还需要配置spring的aop。

至于aop不了解的话:http://blog.csdn.net/ya_1249463314/article/details/63684853

bean.xml里面也配置了DataSourceTransactionManager,这个是配置jdbc连接使用的管理器。配置事务增强就是定义在哪个方法上使用事务管理。

至于注入,使用的上面set方式注入的属性。

至于注入不了解的话:http://blog.csdn.net/ya_1249463314/article/details/53153030

测试类:

public class App {

	public static void main(String[] args) {
		ApplicationContext ac = new ClassPathXmlApplicationContext(
				"cn/spy/transaction/xml/bean.xml");
		UserService userService = (UserService) ac.getBean("userService");
		User user = new User(14, "谭盐盐", "女");
		userService.saveUser(user);
	}
}
结果:


解释:由于数字异常,事务控制导致数据未添加进去,保证了原子性。

4.注解方式实现spring的事务管理

UserDao.java:

@Repository
public class UserDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    public void save(User user) {
        String sql = "insert into myuser(id,username,gender) values(?,?,?)";
        jdbcTemplate.update(
                sql,
                new Object[] { user.getId(), user.getUsername(),
                        user.getGender() }, new int[] { Types.INTEGER,
                        Types.VARCHAR, Types.VARCHAR });
    }
}

UserService.java:

@Service
public class UserService {

	@Autowired
	private UserDao userDao;
	
	@Transactional(readOnly=false)
	public void saveUser(User user) {
		userDao.save(user);
		int i = 1 / 0;
		userDao.save(user);
	}
}

解释:Transactional注解常用的属性:

1)readOnly=false:开启读写事务。

(2)timeout=-1:事务的超时时间(-1代表超时时间不限制)。

(3)noRollbackFor=ArithmeticException.class:遇到数学异常不回滚。

(4)isolation=Isolation.DEFAULT:事务的隔离级别,数据库的默认。

(5)propagation=Propagation.REQUIRED:事务的传播行为。

bean.xml:

<!-- 1. 数据源对象: C3P0连接池 -->
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
		<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/basicjdbc?characterEncoding=utf-8"></property>
		<property name="user" value="root"></property>
		<property name="password" value=""></property>
		<property name="initialPoolSize" value="3"></property>
		<property name="maxPoolSize" value="10"></property>
		<property name="maxStatements" value="100"></property>
		<property name="acquireIncrement" value="2"></property>
	</bean>
	
	<!-- 配置jdbcTemplate工具类实例 -->
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	
	<!-- 开启注解扫描 -->
	<context:component-scan base-package="cn.spy.transaction.annotation"></context:component-scan>
	
	<!-- 指定注解方式实现事务 -->
	<tx:annotation-driven transaction-manager="txManager"/>
	
	<!-- 配置事务管理器类 -->
	<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>

解释:由于采用注解注入的方式,所以要配置扫描注解,并且要开启注解方式实现事务。至于事务管理器类是必须要配置的。

测试类:

public class App {

	public static void main(String[] args) {
		ApplicationContext ac = new ClassPathXmlApplicationContext(
				"cn/spy/transaction/annotation/bean.xml");
		UserService userService = (UserService) ac.getBean("userService");
		User user = new User(14, "谭盐盐", "女");
		userService.saveUser(user);
	}
}
结果:


结果:由于数字异常,导致数据没有保存到数据库,维持了事务的原子性。




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值