Spring事务(声明式、注解)实现

一:环境搭建

1:maven依赖

<!-- Spring -->
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-context</artifactId>
	<version>4.3.12.RELEASE</version>
</dependency>

<!-- aop -->
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-aspects</artifactId>
	<version>4.3.12.RELEASE</version>
</dependency>

<!-- 事务 -->
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-tx</artifactId>
	<version>4.3.12.RELEASE</version>
</dependency>

<!-- jdbc数据访问 -->
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-jdbc</artifactId>
	<version>4.3.12.RELEASE</version>
</dependency>

<!-- mysql数据库连接驱动 -->
<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
	<version>6.0.6</version>
</dependency>

<!-- dhcp连接池 -->
<dependency>
	<groupId>commons-dbcp</groupId>
	<artifactId>commons-dbcp</artifactId>
	<version>1.4</version>
</dependency>

<!-- 单元测试 -->
<dependency>
	<groupId>junit</groupId>
	<artifactId>junit</artifactId>
	<version>4.12</version>
	<scope>test</scope>
</dependency>

2:项目目录

3:编写Controller、Service、Dao层代码

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import com.mote.service.UserService;

@Controller
public class UserController {

	@Autowired
	private UserService userService;
	
	public void addUser() {
		userService.addUser();
	}
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.mote.dao.UserDao;

@Service
public class UserService {

	@Autowired
	private UserDao userDao;

	public void addUser() {
		userDao.addUser();
		//int b = 1/0; //制造异常
	}
}
import org.apache.commons.dbcp.BasicDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

@Repository
public class UserDao {

	@Autowired
	private BasicDataSource dataSource;

	public void addUser() {
		JdbcTemplate template = new JdbcTemplate(dataSource); //创建JDBC模板,操作数据库
			
		String sql = "INSERT INTO debo_role (NAME, AGE) VALUES (?, ?)";
			
		template.update(sql, "super",22); //执行sql语句
	}
}

二:声明式事务

1:编写 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:aop="http://www.springframework.org/schema/aop"
	xmlns:context="http://www.springframework.org/schema/context" 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/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
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">

	<!-- 包扫描:将配置了@Controller、@Service、@Repository、@Compoment注解的组件添加到Spring容器 -->
	<context:component-scan base-package="com.mote" />

	<!-- 配置数据源 -->
	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
		<!-- mysql连接驱动jar版本为6.06,驱动类由com.mysql.jdbc.Driver变为com.mysql.cj.jdbc.Driver -->
		<property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
		<property name="url" value="jdbc:mysql://114.215.83.3:3306/debo" />
		<property name="username" value="root" />
		<property name="password" value="123456" />
	</bean>

	<!-- 定义事务管理器 -->
	<bean id="transactionManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource" />
	</bean>

	<!-- 配置事务特性 -->
	<tx:advice id="adviceRef" transaction-manager="transactionManager">
		<tx:attributes>
			<!-- add*:匹配以add为开头的所有方法,符合此命名规则的方法作为一个事务。 
			REQUIRED:若当前没有事务,就新建一个事务,若存在一个事务中,加入该事务中。这是最常见的选择 -->
			<tx:method name="add*" propagation="REQUIRED" />
			<tx:method name="del*" propagation="REQUIRED" />
			<tx:method name="upd*" propagation="REQUIRED" />
			<tx:method name="get*" propagation="REQUIRED" />
			<tx:method name="*" read-only="true" rollback-for="Exception" />
		</tx:attributes>
	</tx:advice>

	<!-- 配置切点(需要加事务类、方法),并切入事务 -->
	<aop:config>
		<!-- 配置事务切点 -->
		<aop:pointcut id="cutPoint"
			expression="execution(public * com.mote.service.*.*(..))" />
		<!-- 切入事务 -->
		<aop:advisor pointcut-ref="cutPoint" advice-ref="adviceRef" />
	</aop:config>

</beans>

2:测试代码

@Test
public void testXml() {
	// 创建容器
	ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

	// 从容器中获取bean
	UserController userController = context.getBean(UserController.class);

	// 调用方法
    userController.addUser();
}

结果显示:若Service层出现异常,事务回滚成功

三:纯注解

1:编写配置类

import org.apache.commons.dbcp.BasicDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@EnableTransactionManagement// 开启基于注解的事务管理功能
@Configuration// 标注这是一个配置类
@ComponentScan("com.mote")// 包扫描,将@Controller,@Service,@Repostory,@Compoment组件注册到Spring容器
public class MainConfig {

	@Bean// 配置数据源
	public BasicDataSource dataSource() {
		BasicDataSource dataSource = new BasicDataSource();
		dataSource.setUrl("jdbc:mysql://114.215.83.3:3306/debo");
		dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
		dataSource.setUsername("root");
		dataSource.setPassword("123456");
		return dataSource;
	}

	@Bean// 配置事务管理器
	public DataSourceTransactionManager dataSourceManager(
			BasicDataSource dataSource) {
		return new DataSourceTransactionManager(dataSource);
	}

}

2:修改UserDao,添加@Transactional

@Repository
public class UserDao {

	@Autowired
	private BasicDataSource dataSource;

	@Transactional //标注这是一个事务方法
	public void addUser() {
		JdbcTemplate template = new JdbcTemplate(dataSource); //创建JDBC模板,操作数据库
			
		String sql = "INSERT INTO user (NAME, AGE) VALUES (?, ?)";
			
		template.update(sql, "super",22); //执行sql语句
	}
}

3:测试

@Test
public void test() {
	// 创建容器
	AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);

	// 从容器中获取bean
	UserController userController = context.getBean(UserController.class);

	// 调用方法
	userController.addUser();
}

tip 1:@Transactional标注在类上面, 表示类中所有方法都进行事物控制

而当类中某些方法不需要添加事务时:@Transactional(propagation =Propagation.NOT_SUPPORTED)

@Repository
@Transactional
public class UserDao {

	@Autowired
	private BasicDataSource dataSource;

	@Transactional(propagation =Propagation.NOT_SUPPORTED)
	public void addUser() {
		JdbcTemplate template = new JdbcTemplate(dataSource); //创建JDBC模板,操作数据库
			
		String sql = "INSERT INTO debo_role (NAME, COMPANY_ID, DESCRIPTION) VALUES (?, ?, ?)";
			
		template.update(sql, "super",1,"管理员"); //执行sql语句
	}
}

tip 2:切点表达式书写规则

表达式模板:execution(修饰符  返回值  包.类.方法名(参数) throws异常)

  修饰符,一般省略

    public 公共方法

               * 任意

  返回值,不能省略

    void 返回没有值

    String 返回值字符串

    * 任意

  

    com.zby.service  固定包

    com.zby.oa.*.service oa包下面子包 (例如:com.zby.oa.flow.service)

    com.zby.oa..   oa包下面的所有子包(含自己)

    com.zby.oa.*.service.. oa包下面任意子包,固定目录service,service目录任意包

  

    UserServiceImpl 指定类

    *Impl 以Impl结尾

    User* 以User开头

    * 任意

  方法名,不能省略

    addUser 固定方法

    add* 以add开头

    *Do 以Do结尾

    * 任意

  (参数)

    () 无参

    (int) 一个整型

    (int ,int) 两个

    (..) 参数任意

  throws ,可省略,一般不写

猜你喜欢

转载自blog.csdn.net/qq_37936542/article/details/82426848