文章目录

  • 事务操作
  • 1 事务?
  • 2 搭建事务操作环境
  • 3 Spring中事务管理
  • 4 声明式事务管理
  • 4.1 注解方式
  • 4.2 事务参数
  • 4.2.1 事务传播行为
  • 4.2.2 事务隔离级别
  • 4.3 XML方式
  • 4.4 完全注解方式


事务操作

1 事务?

(1)事务是操作数据库最基本的单元,逻辑上的一组操作,要么都成功,要么有一个失败所以操作都失败

(2)事务ACID四大特性:原子性、一致性、隔离性、持久性

2 搭建事务操作环境

前提:银行转账案例,一个存钱一个取钱方法

1、创建数据库表,添加记录(id、username、money)

2、创建service,搭建dao,完成对象的创建和关系注入

service注入dao,在dao注入JdbcTemplate模板,在JdbcTemplate注入DataSource
<?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"
 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">
<!--开启组件扫描-->
<context:component-scan base-package="com.znv.spring.demo5"></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://master:3306/user_db"></property>
  <property name="username" value="root"></property>
  <property name="password" value="123456"></property>
</bean>

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

</beans>@Service
public class UserService {
//注入Dao
@Autowired
private UserDao userDao;
}@Repository
public class UserDaoImpl implements UserDao {
@Autowired
private JdbcTemplate jdbcTemplate;
}

3、在Dao里面创建两个方法:多钱和少钱的方法,在service创建方法

@Service
public class UserService {
//注入Dao
@Autowired
private UserDao userDao;

//转账的方法
public void accountMoney() {
  //少钱
  userDao.reduceMoney();

  //多钱
  userDao.addMoney();
}
}@Repository
public class UserDaoImpl implements UserDao {

@Autowired
private JdbcTemplate jdbcTemplate;

//存钱
@Override
public void addMoney() {
  String sql = "update t_account set money = money-? where username=?";
  jdbcTemplate.update(sql,100,"xiaoyoupei");
}

//取钱
@Override
public void reduceMoney() {
  String sql = "update t_account set money = money+? where username=?";
  jdbcTemplate.update(sql,100,"liyan");
}
}

4、缺点?

上述代码,在执行的时候没有任何问题,但如果产生异常?

那就需要用事务进行解决,具体操作:

try {
      //第一步 开启事务

      //第二步 进行业务操作
      //少钱
      userDao.reduceMoney();

      //多钱
      userDao.addMoney();

      //第三步 没有发生异常,提交事务
  } catch (Exception e) {
      //第四步 出现异常,事务回滚

  }
}

3 Spring中事务管理

1、事务一般添加到Service层(业务逻辑层)

2、Spring内事务管理操作

(1)两种方式:编程式事务管理、声明式事务管理(一般选择)

3、声明式事务管理

(1)基于注解方式(一般选择)

(2)基于xml配置文件方式

4、在Spring进行声明式事务管理,底层使用AOP

5、Spring事务管理API

提供一个接口,代表事务管理器,这个接口针对不同的框架提供不同的实现类

4 声明式事务管理

4.1 注解方式

1、Spring配置文件内配置事务管理器

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

2、Spring配置文件中开启事务注解

(1)在Spring配置文件中引入名称空间

<?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: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/tx http://www.springframework.org/schema/tx/spring-tx.xsd
                     http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

(2)开启事务注解

<!--开启事务注解-->
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>

3、在Service类上面(获取service类里面的方法上面)添加事务注解

(1)@Transactional 可以添加到类上面,也可以添加到方法上

(2)添加类,那就所有方法都添加了事务,如果只添加方法,那就该方法添加了事务

@Service
@Transactional
public class UserService {
......
}

4.2 事务参数

1、在Service类上面添加注解@Template,在这个注解上可以配置事务相关参数

java一个事务中怎么开一个新事务_bc

2、propagation:事务传播行为 看4.2.1

3、isolation:事务隔离级别 看4.2.2

4、timeout:超时时间,事务需要在一定的时间内提交,如果不提交则回滚。默认是-1,设置时间是以秒为单位

5、readonly:是否只读,读就是查询操作,写就是添加修改删除操作,readonly默认值false,表示可以查询,也可以添加修改删除操作。设置成true后只能进行查询的操作

6、rollbackFor:回滚,设置出现哪些异常进行事务回滚

7、noRollbackFor:不回滚,设置出现哪些异常不进行事务的回滚

4.2.1 事务传播行为

多事务方法直接调用,这个过程中事务是如何进行管理的

java一个事务中怎么开一个新事务_数据库_02

前提:

@Transactional public void add(){ //调用update方法 update(); } public void update(){ }

Spring框架事务传播行为有7种,下面列举典型两种

REQUIRED:如果add方法本身就有事务,调用update方法后,update使用当前add方法里面的事务;如果add方法本身没有事务,调用update方法后,创建新事务

REQUIRED_NEW:使用add方法调用update方法,无论add是否有事务,都会创建新的事务

实现

@Transactional(propagation = Propagation.REQUIRED)
4.2.2 事务隔离级别

(1)事务有隔离性,多事务之间操作不会产生影响,不考虑隔离性产生的问题

(2)三个读问题:脏读、不可重复读、幻读

(3)三个读的解释

脏读:一个未提交事务读取到另外一个未提交事务的数据 不可重复读:一个未提交的事务读到另外一个已提交的事务 幻读:一个未提交的事务读取到另外一个事务添加数据

(4)隔离级别

java一个事务中怎么开一个新事务_java一个事务中怎么开一个新事务_03

(5)如何设置

@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ) //isolation参数

mysql默认可重复读

4.3 XML方式

1、在spring配置文件中进行配置

(1)配置事务管理器

(2)配置通知

(3)配置切入点切面

<!--1 创建事务管理器-->
   <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
       <!--注入数据源-->
       <property name="dataSource" ref="dataSource"></property>
   </bean>

   <!--2 配置通知-->
   <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.znv.spring.demo6.service.UserService.*(..))"/>
       <!--配置切面-->
       <aop:advisor advice-ref="txadvice" pointcut-ref="pt"/>
   </aop:config>

4.4 完全注解方式

创建配置类,使用配置类替代xml配置文件

@Configuration
@ComponentScan(basePackages = "com.znv.spring.demo6") //开启组件扫描
@EnableTransactionManagement //开启事务
public class TxConfig {

   //创建数据库的连接池
   @Bean
   public DruidDataSource getDruidDataSource() {
       DruidDataSource dataSource = new DruidDataSource();
       dataSource.setDriverClassName("com.mysql.jdbc.Driver");
       dataSource.setUrl("jdbc:mysql://master:3306/user_db");
       dataSource.setUsername("root");
       dataSource.setPassword("123456");
       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 dataSourceTransactionManager = new DataSourceTransactionManager();
       dataSourceTransactionManager.setDataSource(dataSource);
       return dataSourceTransactionManager;
   }

}