spring tx

本文详细介绍了如何使用Spring的JdbcTemplate进行数据库操作,包括环境配置、Dao层和DaoImpl的实现,以及事务管理的概念、生活场景、问题原因、解决方案和ACID特性。同时,展示了在Spring中如何通过注解和XML配置实现事务管理,以及事务的传播行为和隔离级别。
摘要由CSDN通过智能技术生成

1、Jdbctemplate

目标,使用spring管理jdbc框架,对指定表实现增删改查,批量增删改的效果,使用过程与queryrunner-99%相似

(1)、环境配置

A.jar包

在这里插入图片描述

B.Sql

DROP TABLE IF EXISTS `course`;
CREATE TABLE `course`  (
  `c_id` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
  `c_name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL DEFAULT '',
  `t_id` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
  PRIMARY KEY (`c_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin ROW_FORMAT = Dynamic;

INSERT INTO `course` VALUES ('01', '语文', '02');
INSERT INTO `course` VALUES ('02', '数学', '01');
INSERT INTO `course` VALUES ('03', '英语', '03');

C.命名空间引入

<?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.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">

D.配置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: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">

	<!-- 配置连接池 -->
	<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
		<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
		<property name="url" value="jdbc:mysql:///demo"></property>
		<property name="username" value="root"></property>
		<property name="password" value="root"></property>
	</bean>
	<!-- jdbcTemplate 对象 -->
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<!-- 注入dataSource -->
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	<!-- 注解扫描 -->
	<context:component-scan base-package="com.tx"></context:component-scan>




</beans>       

(2)、Dao层配置

package com.tx.dao;

import java.util.List;

import com.tx.pojo.Course;

public interface CourseDao {
	//常规jdbc
	public void insertCourse(Course course);//增加课程
	public void updateCourse(Course course);//修改课程
	public void deleteById(String id);//删除课程
	public int countAll();//查询count计数
	public Course getById(String id);//根据id查询
	public List<Course> getAllCourse();//查询课程列表
	//批量增删改
	public void batchAdd(List<Object[]> batchParams);//批量增加课程参数
	public void batchUpdate(List<Object[]> batchParams);//批量修改课程参数
	public void batchDelete(List<Object[]> batchParams);//批量删除课程参数
}

(3)、DaoImpl实现

A.DI(依赖注入)- jdbc框架

@Repository
public class CourseDaoImpl implements CourseDao {
	
	@Autowired
	private JdbcTemplate jdbcTemplate;

B.增删改

@Override
	public void insertCourse(Course course) {
		String sql ="insert into course values(?,?,?)";
		Object[] params= {course.getCid(),course.getCname(),course.getTid()};
		int update=jdbcTemplate.update(sql, params);
		System.out.println(update);
	}

	@Override
	public void updateCourse(Course course) {
		String sql ="update course set c_name=?,t_id=? where c_id=?";
		Object[] params= {course.getCname(),course.getTid(),course.getCid()};
		jdbcTemplate.update(sql, params);
	}

	@Override
	public void deleteById(String id) {
		String sql ="delete from course where c_id=?";
		jdbcTemplate.update(sql, id);
	}
a.对应service层
@Service
public class CourseService {
	@Autowired
	private CourseDao courseDao;
	
	public void addCource(Course course) {
		courseDao.insertCourse(course);
	}
	
	public void updateCourse(Course course) {
		courseDao.updateCourse(course);
	}
	
	public void deleteCourse(String id) {
		courseDao.deleteById(id);
	}

C.查询个数,单行记录,多行记录

a.RowMapper 引入——类比queryrunner之ResultSetHandler

RowMapper 是接口,针对返回不同类型数据,使用这个接口里面实现类完成 数据封装

@Override
	public int countAll() {
		String sql="select count(c_id) from course";
		Integer count=jdbcTemplate.queryForObject(sql, Integer.class);
		return count;
	}

	@Override
	public Course getById(String id) {
		String sql="select c_id cid,c_name cname,t_id tid from course where c_id";
		Object[] params= {id};
		//BeanProperRowMapper 实体属性行mapper
		Course course=jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<Course>(Course.class),params);
		return course;
	}

	@Override
	public List<Course> getAllCourse() {
		String sql = "select c_id cid,c_name cname,t_id tid from course";
		//调用方法
		List<Course> courseList = jdbcTemplate.query(sql,new BeanPropertyRowMapper<Course>(Course.class), null);
		return courseList;
	}
b.对应service层

public void countAll() {
System.out.println(“总数为:”+courseDao.countAll( ));
}

public void queryForBean( String id) {
	Course course=courseDao.getById(id) ;
	System.out.println( course);
}

public void queryForBeanList() {
	List<Course> list=courseDao.getAllCourse();
	for(Course course : list) {
		System.out.println(course);
	}
}

D.批量增删改

//批量增加
	@Override
	public void batchAdd(List<Object[]> batchParams) {
		String sql = "insert into course values( ? , ?, ?)";
		int[] ints = jdbcTemplate.batchUpdate(sql, batchParams);
		System.out.println(Arrays.toString( ints));
	}
	//批量修改
	@Override
	public void batchUpdate(List<Object[]> batchParams) {
		String sql = "update course set c_name=?,t_id=? where c_id=?";
		int[] ints = jdbcTemplate.batchUpdate(sql, batchParams);
		System.out.println(Arrays.toString(ints));
	}
	//批量删除@Override
	public void batchDelete(List<Object[]> batchParams) {
		String sql = "delete from course where c_id=?";
		int[] ints = jdbcTemplate.batchUpdate(sql, batchParams);
		System.out.println(Arrays.toString(ints));
	}
对应service层
public void batchAdd(List<Object[]> batchParams) {
		courseDao.batchAdd(batchParams ) ;
	}
	
	public void batchUpdate(List<Object[]> batchParams) {
		courseDao.batchUpdate( batchParams ) ;
	}
	public void batchDelete(List<Object[]> batchParams){
		courseDao.batchDelete( batchParams);
	}

(4)、测试

package com.tx.test;

import java.util.ArrayList;
import java.util.List;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.tx.pojo.Course;
import com.tx.service.CourseService;

public class DemoTest {
	@Test
	public void addTest() {
		ApplicationContext context =
				 new ClassPathXmlApplicationContext("bean1.xml");
		CourseService courseService=context.getBean("courseService",CourseService.class);
		Course course=new Course("04","哲学","01");
		courseService.addCource(course);;
	}
	
	@Test
	public void updateTest() {
		ApplicationContext context =
				 new ClassPathXmlApplicationContext("bean1.xml");
		CourseService courseService=context.getBean("courseService",CourseService.class);
		Course course=new Course("04","美术","02");
		courseService.updateCourse(course);
	}
	
	@Test
	public void deleteTest() {
		ApplicationContext context =
				 new ClassPathXmlApplicationContext("bean1.xml");
		CourseService courseService=context.getBean("courseService",CourseService.class);
		courseService.deleteCourse("04");
	}
	@Test
	public void countTest() {
		ApplicationContext context =
				 new ClassPathXmlApplicationContext("bean1.xml");
		CourseService courseService=context.getBean("courseService",CourseService.class);
		courseService.countAll();;
	}
	@Test
	public void queryForBeanTest() {
		ApplicationContext context =
				 new ClassPathXmlApplicationContext("bean1.xml");
		CourseService courseService=context.getBean("courseService",CourseService.class);
		courseService.queryForBean("01");
	}
	@Test
	public void queryForBeanListTest() {
		ApplicationContext context =
				 new ClassPathXmlApplicationContext("bean1.xml");
		CourseService courseService=context.getBean("courseService",CourseService.class);
		courseService.queryForBeanList();
	}
	@Test
	public void batchAddTest() {
		ApplicationContext context =
				 new ClassPathXmlApplicationContext("bean1.xml");
		CourseService courseService=context.getBean("courseService",CourseService.class);
		//批量添加测试
		List<Object[]> batchParams = new ArrayList<>();
		Object[] o1 = {"04","物理","04"};
		Object[] o2 = {"05","化学","05"};
		Object[] o3 = {"06","生物","06"};
		batchParams.add(o1);
		batchParams.add(o2);
		batchParams.add(o3);
		//调用批量添加
		courseService.batchAdd(batchParams);
	}
	@Test
	public void batchUpdateTest() {
		ApplicationContext context =
				 new ClassPathXmlApplicationContext("bean1.xml");
		CourseService courseService=context.getBean("courseService",CourseService.class);
		//批量添加测试
		List<Object[]> batchParams = new ArrayList<>();
		Object[] o1 = {"04","化学","04"};
		Object[] o2 = {"05","生物","05"};
		Object[] o3 = {"06","物理","06"};
		batchParams.add(o1);
		batchParams.add(o2);
		batchParams.add(o3);
		//调用批量添加
		courseService.batchUpdate(batchParams);
	}
	@Test
	public void batchDeleteTest() {
		ApplicationContext context =
				 new ClassPathXmlApplicationContext("bean1.xml");
		CourseService courseService=context.getBean("courseService",CourseService.class);
		//批量添加测试
		List<Object[]> batchParams = new ArrayList<>();
		Object[] o1 = {"04"};
		Object[] o2 = {"05"};
		Object[] o3 = {"06"};
		batchParams.add(o1);
		batchParams.add(o2);
		batchParams.add(o3);
		//调用批量添加
		courseService.batchDelete(batchParams);
	}
}

2、事务管理

(1)、生活场景

当我们注册平夕夕的时候,app会给我们发代金券或者优惠券,如果注册成功了没有发,或者没有注册成功却领了对应的券,用户体验就非常不好。要么注册成功就能领到券,要么没有注册成功就根本无法领到券,本质是多条sql要么全部执行成功,要么就全部失败

(2)、问题原因

在这里插入图片描述

使用sql直接操作数据库,很容易产生读写问题(内部,外部异常)
内部异常:执行一套课程数据更新sql,数据库突然重启,丢失更新语句,无原始记录对比
外部异常:如上,条件为电脑重启

(3)、解决方案

不让sql直接操作数据库,采用记录日志的过程解决,这种技术就是事务机制
在这里插入图片描述

Mysql中一共有5种日志文件,采用其中的redo日志和undo日志完成问题解决
Sql语句操作什么记录,这些记录会被复制到undo日志中(from后面跟的表),然后增删改查操作的结果会复制到redo日志中,假如这些增删改查的操作没有什么问题,最后把redo日志同步到数据库数据文件中,即便中途在同步过程中出现了问题,恢复之后继续让redo日志继续和数据文件进行同步即可,这样的操作依赖,数据库抵抗风险的能力得到加强

(4)、事务定义

事务(Transaction)是一个或者多个sql语句组成的整体,要么全部执行成功,要么全部执行失败,mysql一条sql的默认事务是自动开启,但是对于多条sql组合成的在外界看起来是一次操作的流程(要么全都执行成功,要么全都执行失败)需要保证他们在同一个事务之下

(5)、数据库使用案例

案例:删除接待部门,需要将该部门下的原来员工全部拷贝进入后勤部门,再执行删除部门操作,整个操作在外部操作人员来看就是“删除接待部门这一件事”,但实际上内部操作有两条步骤,要么都成功,要么都失败后回到初始状态

在这里插入图片描述

(6)、ACID

A.A-事务原子性-不可分割-看着单位一

原子——>分子
对于事务来说,从【开启事务–多条sql执行–提交事务】这整个过程就是原子性的,不可分割的,要么全部执行成功形成一次使用者眼中的功能(删除部门案例),要么就什么都没执行,回滚到执行前的样子

B.C-事务的一致性

在这里插入图片描述

不管任何时间,并发多少,事务必须保证运行结果的一致性
如何保证呢?阻止事务之间相互读取没有提交的临时数据,一个事务不能读取另外一个事务的undo和redo日志

C.I-事务隔离性

为了结果的一致性,机制上看就是事务的隔离机制起效果
在这里插入图片描述

D.D-事务持久性

事务一旦提交,结果便是永久性的,即便发生异常,仍然可以依靠事务日志完成数据的持久化,无论如何数据都可以依靠事务提交到数据文件中

E.开发中的事务使用

在这里插入图片描述

由于事务一般管控多条sql执行一个生活业务操作集合,所以最好将事务打在service层面
a.Jdbc层面开启事务
参考web应用案例中Daofactory的事务aop设计
b.Spring管理事务(AOP-aspecj技术实现)
事务切入点在类上,代表该类所有方法执行事务管理
切入点在方法上,该方法执行事务管理
① 注解配置事务管理
环境:

配置xml

<?xml version="1.0" encoding="UTF-8"?>

<!-- 注解扫描 -->                        
<context:component-scan base-package="com.tx.annconfig"></context:component-scan>  

<!-- 配置连接池 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
	<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
	<property name="url" value="jdbc:mysql:///demo"></property>
	<property name="username" value="root"></property>
	<property name="password" value="root"></property>
</bean>   

<!-- jdbcTemplate 对象 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
	<!-- 注入dataSource -->
	<property name="dataSource" ref="dataSource"></property>
</bean>

<!-- 创建事务管理器  -->                    
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
	<!-- 注入数据源 -->
	<property name="dataSource" ref="dataSource"></property>
</bean> 
 
<!-- 开启事务 -->                  
<tx:annotation-driven transaction-manager="transactionManager"/>       

CourseService.java
package com.tx.ann;

public interface CourseService {

public void updateCourse(Course c1, Course c2);

}

对应的service实现类
package com.tx.ann;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service(“service”)
public class CourseServiceImpl implements CourseService {

@Autowired
private CourseDao courseDao;

@Transactional
@Override
public void updateCourse(Course c1, Course c2) {
	courseDao.updateCourse(c1);
	int i = 10/0;
	courseDao.updateCourse(c2);
	
}

}

测试类
package com.tx.ann;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class DemoTest {

@Test
public void updateTest() {
	// 加载spring配置文件
	ApplicationContext context = new ClassPathXmlApplicationContext("com/tx/ann/bean.xml");
	// 获取配置创建对象
	CourseService service = context.getBean("service", CourseService.class);
	
	Course c1 = new Course("01","数学","02");
	Course c2 = new Course("02","语文","01");
	
	service.updateCourse(c1, c2);
	
}

}

② xml配置事务管理
环境:

配置xml

<?xml version="1.0" encoding="UTF-8"?>

<!-- 配置连接池 -->        
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
	<!-- 加载驱动 -->
	<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
	<property name="url" value="jdbc:mysql:///demo"></property>
	<property name="username" value="root"></property>
	<property name="password" value="root"></property>
</bean>
    
<!-- jdbcTemplate对象 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
	<!-- 注入DataSource -->
	<property name="dataSource" ref="dataSource"></property>
</bean>

<!-- 注解扫描包 -->
<context:component-scan base-package="com.tx.xmlconfig"></context:component-scan>

<!-- 开启事务管理 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
	<!-- 注入DataSource -->
	<property name="dataSource" ref="dataSource"></property>
</bean>


<!-- 开启事务声明 -->
<tx:advice id="transactionAdvice" transaction-manager="transactionManager">
	<tx:attributes>
		<!-- requied 都得开启事务 -->
		<tx:method name="insert*" propagation="REQUIRED"/>
		<tx:method name="update*" propagation="REQUIRED"/>
		<tx:method name="edit*" propagation="REQUIRED"/>
		<tx:method name="save*" propagation="REQUIRED"/>
		<tx:method name="add*" propagation="REQUIRED"/>
		<tx:method name="new*" propagation="REQUIRED"/>
		<tx:method name="set*" propagation="REQUIRED"/>
		<tx:method name="remove*" propagation="REQUIRED"/>
		<tx:method name="delete*" propagation="REQUIRED"/>
		<tx:method name="change*" propagation="REQUIRED"/>
		<!-- read-only  只读,不开启事务 -->
		<tx:method name="get*" propagation="REQUIRED" read-only="true"/>
		<tx:method name="find*" propagation="REQUIRED" read-only="true"/>
		<tx:method name="select*" propagation="REQUIRED" read-only="true"/>
		<tx:method name="load*" propagation="REQUIRED" read-only="true"/>
	</tx:attributes>
</tx:advice>

<!-- 开启事务切面管理 -->
<aop:config>
	<!-- 配置切点 -->
	<aop:pointcut expression="execution(* com.tx.xmlconfig.*.*(..))" id="serviceMethod"/>
	<!-- < aop:aspect>大多用于日志,缓存 -->
	<!-- < aop:advisor>大多用于事务管理 -->
	<!-- 区别在于 -->
	<!--juge yes:  setAutoCommit(false)  commit  rollback  no:read-only -->
	<aop:advisor advice-ref="transactionAdvice" pointcut-ref="serviceMethod"/>
</aop:config>

<!-- 指定数据库,druid无法识别由spring动态代理后的Proxy -->
 <bean id="wall-filter" class="com.alibaba.druid.wall.WallFilter">
    <property name="dbType" value="mysql" />
</bean>

其他类与注解配置一样

③ 完全注解方式
环境:

配置配置类
txConfig.java替换xml
package com.tx.ann;

import javax.sql.DataSource;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import com.alibaba.druid.pool.DruidDataSource;

@Configuration //配置类
@ComponentScan(basePackages = “com.tx.ann”) // 包扫描
@EnableTransactionManagement // 开启事务
public class TxConfig {

// 创建数据库连接池
@Bean
public DruidDataSource getDruidDataSource() {
	DruidDataSource dataSource = new DruidDataSource();
	dataSource.setDriverClassName("com.mysql.jdbc.Driver");
	dataSource.setUrl("jdbc:mysql:///demo");
	dataSource.setUsername("root");
	dataSource.setPassword("root");
	return dataSource;
}

// 创建jdbcTemplate对象
@Bean
public JdbcTemplate getJdbcTemplate(DataSource dataSource) {
	// 到ioc容器中根据类型找到DataSource
	JdbcTemplate jdbcTemplate = new JdbcTemplate();
	// 注入DataSource
	jdbcTemplate.setDataSource(dataSource);
	return jdbcTemplate;		
}

// 创建事务管理器
@Bean
public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource) {
	// 连接池事务管理器
	DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
	// 注入DataSource
	transactionManager.setDataSource(dataSource);
	return transactionManager;
}

}

c.事务参数
① Propagation:事务传播
多事务方法调用(嵌套使用事务)
Spring框架的7种事务传播行为

工程环境:

bean1.xml

<?xml version="1.0" encoding="UTF-8"?>

<!-- 配置连接池 -->                 
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
	 <property name="url" value="jdbc:mysql:///demo" />
	 <property name="username" value="root" />
	 <property name="password" value="root" />
	 <property name="driverClassName" value="com.mysql.jdbc.Driver" />
</bean>
    
<!-- JdbcTemplate 对象 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
 	<!--注入 dataSource-->
 	<property name="dataSource" ref="dataSource"></property>
</bean>

<!-- 注解扫描 -->
<context:component-scan base-package="com.tx.propagation">
</context:component-scan>

<!--创建事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

<!--注入数据源-->
	<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 开启注解配置 -->
<tx:annotation-driven transaction-manager="transactionManager" /> 
StuService.java package com.tx.propagation; public interface StuService { public void saveParent(); public void saveChildren(); } StuServiceImpl.java package com.tx.propagation;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
public class StuServiceImpl implements StuService{
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public void saveParent() {
Stu stu=new Stu();
stu.setName(“parent”);
stu.setAge(30);
String sql=“insert into stu (name,age) values (?,?)”;
Object[] params= {stu.getName(),stu.getAge()};
jdbcTemplate.update(sql, params);
}

@Transactional(propagation=Propagation.SUPPORTS)
@Override
public void saveChildren() {
	saveChild1();
	int i=10/0;
	saveChild2();
}
public void saveChild1() {
	Stu stu1=new Stu();
	stu1.setName("child-1");
	stu1.setAge(10);
	String sql="insert into stu (name,age) values (?,?)";
	Object[] params= {stu1.getName(),stu1.getAge()};
	jdbcTemplate.update(sql, params);
}
public void saveChild2() {
	Stu stu1=new Stu();
	stu1.setName("child-2");
	stu1.setAge(20);
	String sql="insert into stu (name,age) values (?,?)";
	Object[] params= {stu1.getName(),stu1.getAge()};
	jdbcTemplate.update(sql, params);
}

}
TestTransactionService.java
package com.tx.propagation;

public interface TestTransactionService {

public void testPropagationTrans();

}

TestTransactionServiceImpl.java
package com.tx.propagation;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service(“service”)
public class TestTransactionServiceImpl implements TestTransactionService{

@Autowired
private StuService stuService;

@Transactional(propagation=Propagation.REQUIRED)
@Override
public void testPropagationTrans() {
	stuService.saveParent();
	stuService.saveChildren();
	int a=10/0;
}

}

TransactionTest.java
package com.tx.propagation;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TransactionTest {

@Test
public void tranTest() {
	ApplicationContext context =new ClassPathXmlApplicationContext("com/tx/propagation/bean1.xml");
	TestTransactionService service=context.getBean("service",TestTransactionService.class);
	service.testPropagationTrans();
}

}

REQUIRED与REQUIRED
有事务则在事务中运行,没事务则开启事务)
(只要有一个报错,就不会有数据加入到数据库)

REQUIRED与SUPPORTS
------下列,不会有数据加入到数据库

REQUIRED与REQUIRES_NEW
内有错,外没错,REQUIRES_NEW开启的新事务会被挂起,则不会添加到数据库
REQUIRED与NEVER
有事务,则抛出异常,所以不会有数据

② ioslation:事务隔离级别
(1)事务有特性成为隔离性,多事务操作之间不会产生影响。不考虑隔离性产生很多问题
(2)有三个读问题:脏读、不可重复读、虚(幻)读
(3)脏读:一个未提交事务读取到另一个未提交事务的数据(开启两个事务,事务A修改了数据,并未提交,事务B读取到事务A未提交的数据)

(4)不可重复读:针对同一个数据,一个未提交事务读到另一个事务已经修改并提交的数据

(5)幻读:每次读都多一条数据,一个未提交事务读取到另一个事务新提交的新增数据(注意:是已提交事务)

脏读是问题,需要解决
不可重复读和幻读是状态,大部分业务里没有太大问题
解决脏读方案:设置隔离级别

③ timeout:超时时间
(1)事务需要在一定时间内进行提交,如果不提交进行回滚
(2)默认值是 -1 ,设置时间以秒单位进行计算

④ readOnly:是否只读
(1)读:查询操作,写:添加修改删除操作
(2)readOnly 默认值 false,表示可以查询,可以添加修改删除操作
(3)设置 readOnly 值是 true,设置成 true 之后,只能查询

⑤ rollbackFor:回滚
(1)设置出现哪些异常进行事务回滚

⑥ noRollbackFor:不回滚
(1)设置出现哪些异常不进行事务回滚

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值