`
JavaCrazyer
  • 浏览: 3008943 次
  • 性别: Icon_minigender_1
  • 来自: 河南
社区版块
存档分类

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

  • 大小: 2.9 KB
  • 大小: 3.2 KB
分享到:
评论

相关推荐

    spring3.0两种事务管理配置

    Spring 3.0 提供了两种事务管理配置方法:基于 XML 的事务管理和基于 @Transactional 的事务管理,这两种方法都是为了实现事务管理的目标,分别具有不同的配置方式和优缺点。 基于 XML 的事务管理 这种方法不需要...

    Spring事务管理4种方式

    本文将详细介绍Spring事务管理的四种方式:编程式事务管理、声明式事务管理、PlatformTransactionManager接口以及TransactionTemplate。 1. **编程式事务管理**:这是一种手动控制事务的方式,通过在代码中调用`...

    Spring事务管理Demo

    首先,Spring提供了两种主要的事务管理方式:编程式事务管理和声明式事务管理。 1. **编程式事务管理**:通过使用`PlatformTransactionManager`接口及其实现类(如`JdbcTemplate`或`HibernateTemplate`),开发者...

    Spring事务管理的三种方式

    本篇文章将详细探讨Spring中的三种事务管理方式:编程式事务管理、声明式事务管理和基于注解的事务管理。 首先,编程式事务管理是通过编码来控制事务的开始、提交、回滚等操作。Spring提供了...

    spring事务管理5种方法

    每种事务管理方法都有其适用场景,选择哪种方式取决于项目需求、团队习惯以及对事务控制的精细程度。理解并灵活运用这五种事务管理方法,能有效提升Spring应用的稳定性和可维护性。在实际开发中,结合源码阅读和工具...

    Spring事务管理开发必备jar包

    2. **Spring事务管理**:Spring提供了两种事务管理方式,即编程式事务管理和声明式事务管理。编程式事务管理通过TransactionTemplate或直接调用PlatformTransactionManager接口的方法来管理事务,而声明式事务管理则...

    Spring事务原理、Spring事务配置的五种方式

    Spring事务原理是指Spring框架中的一种机制,用于管理事务,并提供了多种配置方式。事务是指一系列的操作,作为一个整体执行,如果其中某个操作失败,整个事务将回滚。Spring事务原理围绕着两个核心:...

    Spring事务管理的jar包

    Spring事务管理分为编程式事务管理和声明式事务管理两种方式。编程式事务管理通过使用PlatformTransactionManager接口的begin、commit、rollback等方法直接控制事务的生命周期,这种方式灵活但容易导致代码过于繁琐...

    spring 事务管理的理解

    Spring 提供了两种事务管理方式:编程式事务管理和声明式事务管理。 1. 编程式事务管理:这是通过编写代码来控制事务的开始、提交和回滚。Spring 提供了PlatformTransactionManager接口,如...

    Spring事务管理失效原因汇总

    Spring提供了声明式事务管理和编程式事务管理两种方式,其中声明式事务管理因其实现简单而被广泛应用。声明式事务主要通过Spring AOP(面向切面编程)来实现,它允许在方法执行前后添加事务逻辑而不改变原有代码逻辑。...

    spring事务管理

    Spring事务管理主要包括两种类型:编程式事务管理和声明式事务管理。 - **编程式事务管理**:通过编写代码来控制事务的开始、提交或回滚等操作。这种方式灵活度高,但会使得代码变得冗余且难以维护。 - **声明式...

    spring事务配置的五种方式

    ### Spring事务配置的五种方式详解 #### 一、引言 在企业级应用开发中,事务处理是非常重要的一部分,特别是在涉及多个数据库操作时。Spring框架提供了强大的事务管理功能,支持编程式和声明式两种事务处理方式。...

    spring 自定义事务管理器,编程式事务,声明式事务@Transactional使用

    在Java应用中,Spring提供了两种主要的事务管理方式:编程式事务管理和声明式事务管理。 **编程式事务管理** 是通过调用`PlatformTransactionManager`接口提供的方法来手动控制事务的开始、提交、回滚。例如,你...

    Spring的事务管理小案例

    Spring的事务管理分为编程式事务管理和声明式事务管理两种方式。编程式事务管理需要开发者手动编写事务管理代码,虽然灵活但易出错,且侵入性强。声明式事务管理则是通过配置或注解来声明事务边界,更加简洁且易于...

    spring事务操作试验

    在描述中提到的博客文章中,作者可能详细讲解了如何配置和使用这两种事务管理方式。通常,声明式事务管理是首选,因为它更简洁且易于维护。例如,可以使用@Transactional注解在方法级别声明一个事务,该方法内的所有...

    Spring事务流程图

    在Spring中,事务管理分为编程式和声明式两种方式。本篇文章将详细解释Spring事务管理的流程,以及如何通过时序图来理解这一过程。 首先,我们来看Spring事务的流程。当一个事务开始时,通常会经历以下步骤: 1. *...

    全面分析_Spring_的编程式事务管理及声明式事务管理

    本教程将深入探讨 Spring 的编程式事务管理和声明式事务管理,帮助你理解这两种方式的差异与应用场景。 首先,编程式事务管理依赖于编程的方式显式地控制事务的开始、提交、回滚等操作。它通过实现 `...

    spring事务与数据库操作

    Spring支持两种类型的事务管理:编程式事务管理和声明式事务管理。其中声明式事务管理因其易于使用和维护而被广泛采用。 ##### 1.1 Spring声明式事务介绍 Spring的声明式事务管理是通过配置文件或注解的方式来实现...

    spring_事务管理(实例代码)

    在Spring框架中,事务管理分为编程式事务管理和声明式事务管理两种方式。 一、编程式事务管理 编程式事务管理允许开发者在代码中显式地开始、提交、回滚事务。这种方式虽然灵活,但会使得业务代码变得复杂,不易...

Global site tag (gtag.js) - Google Analytics