Spring事务操作
先附上代码框架
jdbc.properties
prop.driverClass=com.mysql.jdbc.Driver
prop.url=jdbc:mysql://localhost:3306/tb2
prop.userName=root
prop.password=12345678
bean1.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">
<!-- 引入外部属性文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 组件扫描-->
<context:component-scan base-package="com.atguigu"></context:component-scan>
<!-- 配置连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${prop.driverClass}"></property>
<property name="url"
value="${prop.url}"></property>
<property name="username" value="${prop.userName}"></property>
<property name="password" value="${prop.password}"></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"></tx:annotation-driven>-->
</beans>
UserDao
public interface UserDao {
public void addMoney();
public void reduceMoney();
}
UserDaoImpl
@Repository
public class UserDaoImpl implements UserDao{
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public void reduceMoney() {
String sql="update t_account set money=money-? where username=?";
jdbcTemplate.update(sql,100,"lucy");
}
@Override
public void addMoney() {
String sql="update t_account set money=money+? where username=?";
jdbcTemplate.update(sql,100,"mary");
}
}
UserService
@Service
public class UserService {
//注入 dao
@Autowired
private UserDao userDao;
//转账的方法
public void accountMoney() {
//lucy 少 100
userDao.reduceMoney();
//mary 多 100
int i =10/0;
userDao.addMoney();
} }
t_account
两人同时拥有1000¥
test
@Test
public void TestMoney(){
ApplicationContext context=new ClassPathXmlApplicationContext("bean1.xml");
UserService userService =context.getBean("userService",UserService.class);
userService.accountMoney();
}
事务开始
事务正常
金钱设置为1000
开启异常
@Service
public class UserService {
//注入 dao
@Autowired
private UserDao userDao;
//转账的方法
public void accountMoney() {
//lucy 少 100
userDao.reduceMoney();
//mary 多 100
int i =10/0;
userDao.addMoney();
} }
事务操作(注解声明式事务管理)
在 spring 配置文件配置事务管理器
<!--创建事务管理器--> <bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源-->
<property name="dataSource" ref="dataSource"></property>
</bean>
在 spring 配置文件引入名称空间 tx
开启事务注解
<?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">
<!-- 引入外部属性文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 组件扫描-->
<context:component-scan base-package="com.atguigu"></context:component-scan>
<!-- 配置连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${prop.driverClass}"></property>
<property name="url"
value="${prop.url}"></property>
<property name="username" value="${prop.userName}"></property>
<property name="password" value="${prop.password}"></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"></tx:annotation-driven>
</beans>
添加事务注解
在 service 类上面(或者 service 类里面方法上面)添加事务注解
(1)@Transactional,这个注解添加到类上面,也可以添加方法上面
(2)如果把这个注解添加类上面,这个类里面所有的方法都添加事务
(3)如果把这个注解添加方法上面,为这个方法添加事务
@Service
@Transactional
public class UserService {
//注入dao
@Autowired
private UserDao userDao;
public void accountMoney(){
//1.开启事务
//2.进行业务操作
//lucy少100
userDao.reduceMoney();
//模拟异常
int i =10/0;
//mary多100
userDao.addMoney();
//3.没有异常提交事务
// //4.出现异常 事务回滚
}
}
控制台信息
数据库信息
事务操作(声明式事务管理参数配置)
事务的隔离级别:是指若干个并发的事务之间的隔离程度
-
@Transactional(isolation = Isolation.READ_UNCOMMITTED):读取未提交数据(会出现脏读,
不可重复读) 基本不使用 -
@Transactional(isolation = Isolation.READ_COMMITTED):读取已提交数据(会出现不可重复读和幻读)
-
@Transactional(isolation = Isolation.REPEATABLE_READ):可重复读(会出现幻读)
-
@Transactional(isolation = Isolation.SERIALIZABLE):串行化
事务传播行为:如果在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的执行行为
-
TransactionDefinition.PROPAGATION_REQUIRED:
如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认值。 -
TransactionDefinition.PROPAGATION_REQUIRES_NEW:
创建一个新的事务,如果当前存在事务,则把当前事务挂起。 -
TransactionDefinition.PROPAGATION_SUPPORTS:
如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。 -
TransactionDefinition.PROPAGATION_NOT_SUPPORTED:
以非事务方式运行,如果当前存在事务,则把当前事务挂起。 -
TransactionDefinition.PROPAGATION_NEVER:
以非事务方式运行,如果当前存在事务,则抛出异常。 -
TransactionDefinition.PROPAGATION_MANDATORY:
如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。 -
TransactionDefinition.PROPAGATION_NESTED:
如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;
如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。
-
value :主要用来指定不同的事务管理器;
主要用来满足在同一个系统中,存在不同的事务管理器。
比如在Spring中,声明了两种事务管理器txManager1, txManager2.然后,
用户可以根据这个参数来根据需要指定特定的txManager. -
value 适用场景:在一个系统中,需要访问多个数据源或者多个数据库,
则必然会配置多个事务管理器的 -
REQUIRED_NEW:内部的事务独立运行,在各自的作用域中,可以独立的回滚或者提交;
而外部的事务将不受内部事务的回滚状态影响。 -
ESTED 的事务,基于单一的事务来管理,提供了多个保存点。
这种多个保存点的机制允许内部事务的变更触发外部事务的回滚。
而外部事务在混滚之后,仍能继续进行事务处理,即使部分操作已经被混滚。
由于这个设置基于 JDBC 的保存点,所以只能工作在 JDB C的机制。 -
rollbackFor:让受检查异常回滚;即让本来不应该回滚的进行回滚操作。
-
noRollbackFor:忽略非检查异常;即让本来应该回滚的不进行回滚操作。
https://blog.csdn.net/jiangyu1013/article/details/84397366
https://blog.csdn.net/mingyundezuoan/article/details/79017659
@Transactional(readOnly = false,propagation = Propagation.REQUIRED ,isolation = Isolation.REPEATABLE_READ)
事务操作(XML 声明式事务管理)
第一步 配置事务管理器
第二步 配置通知
第三步 配置切入点和切面
bean2.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">
<!-- 引入外部属性文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 组件扫描-->
<context:component-scan base-package="com.atguigu"></context:component-scan>
<!-- 配置连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${prop.driverClass}"></property>
<property name="url"
value="${prop.url}"></property>
<property name="username" value="${prop.userName}"></property>
<property name="password" value="${prop.password}"></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:advice id="txadvice">
<!--配置事务参数-->
<tx:attributes>
<!--指定哪种规则的方法上面添加事务-->
<tx:method name="accountMoney" propagation="REQUIRED"/>
<!--<tx:method name="account*"/>-->
</tx:attributes>
</tx:advice>
<!--3 配置切入点和切面--> <aop:config>
<!--配置切入点-->
<aop:pointcut id="pt" expression="execution(* com.atguigu.spring5.service.UserService.*(..))"/>
<!--配置切面-->
<aop:advisor advice-ref="txadvice" pointcut-ref="pt"/>
</aop:config>
</beans>
测试
@Test
public void TestAccount1(){
ApplicationContext context=new ClassPathXmlApplicationContext("bean2.xml");
UserService userService =context.getBean("userService",UserService.class);
userService.accountMoney();
}
事务操作(完全注解声明式事务管理)
创建配置类,使用配置类替代 xml 配置文件
@Configuration
@ComponentScan(basePackages = "com.atguigu") //组件扫描
@EnableTransactionManagement //开启事务
public class TxConfig {
//数据库连接池
@Bean
public DruidDataSource getDruidDataSource(){
DruidDataSource druidDataSource =new DruidDataSource();
druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
druidDataSource.setUrl("jdbc:mysql://localhost:3306/tb2");
druidDataSource.setUsername("root");
druidDataSource.setPassword("12345678");
return druidDataSource;
}
//创建 JdbcTemplate 对象
@Bean
public JdbcTemplate getJdbcTemplate(DruidDataSource druidDataSource ){
//到 ioc 容器中根据类型找到 dataSource
JdbcTemplate jdbcTemplate =new JdbcTemplate();
//注入datasource
jdbcTemplate.setDataSource(druidDataSource);
return jdbcTemplate;
}
//创建事务管理器
@Bean
public DataSourceTransactionManager
getDataSourceTransactionManager(DataSource dataSource) {
DataSourceTransactionManager transactionManager = new
DataSourceTransactionManager();
transactionManager.setDataSource(dataSource);
return transactionManager;
}
}
测试类
@Test
public void TestAccount2(){
ApplicationContext context=new AnnotationConfigApplicationContext(TxConfig.class);
UserService userService =context.getBean("userService",UserService.class);
userService.accountMoney();
}
Spring整合Mybatis
先附上整体框架
mybatis项目由脚手架生成
bean1.xml添加如下配置
<!-- 注册sqlsessionfactorybean
创建出sqlsessionfactorybean对象-->
<bean id="SqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!-- 指定mybatis主配置文件位置-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
<!-- 注册mapper扫描配置器-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="SqlSessionFactory"/>
<!-- 指定基本扫描包,即Dao接口包-->
<property name="basePackage" value="com.openlab.mapper"/>
</bean>
之后就可以将mybatis配置文件中如下注掉
UserService
@Service
@Transactional
public class UserService {
//注入dao
@Autowired
private UserMapper userMapper;
public int deleteByPrimaryKey(Integer id ){
return userMapper.deleteByPrimaryKey(id);
}
}
这里测试根据id删除User
测试删除id为2的User
@Test
public void mybatis() throws IOException {
ApplicationContext context=new ClassPathXmlApplicationContext("bean1.xml");
UserService userService =context.getBean("userService",UserService.class);
//遍历
int i = userService.deleteByPrimaryKey(2);
System.out.println(i);
}
控制台输出
数据库数据