SpringBoot&MySq中设置默认事务隔离等级详解

设置默认事务隔离

在这里插入图片描述

SpringBoot:

可以在属性文件里配置Spring Boot配置事务默认的隔离级:

#隔离级别数字配置的含义:
#-1 数据库默认隔离级别
#1 未提交读 READ UNCOMMITTED
#2 读写提交 READ COMMITTED
#4 可重复读 REPEATABLE READ
#8 串行化 SERIALIZABLE

#hikari数据源默认隔离级别
spring.datasource.hikari.transaction-isolation=2                            

#tomcat数据源默认隔离级别
spring.datasource.tomcat.default-transaction-isolation=2                            

#dbcp2数据库连接池默认隔离级别
spring.datasource.dbcp2.default-transaction-isolation=2 

MySql:

  1. 可以在my.ini文件中使用transaction-isolation选项来设置服务器的缺省事务隔离级别。

四种级别:

  • READ-UNCOMMITTED
  • READ-COMMITTED
  • REPEATABLE-READ
  • SERIALIZABLE

例如:

[mysqld]

#可选参数有:READ-UNCOMMITTED, READ-COMMITTED, REPEATABLE-READ, SERIALIZABLE
transaction-isolation = READ-COMMITTED
  1. 通过命令动态设置隔离级别:
//设置read uncommitted级别:
set session transaction isolation level read uncommitted;

//设置read committed级别:
set session transaction isolation level read committed;

//设置repeatable read级别:
set session transaction isolation level repeatable read;

//设置serializable级别:
set session transaction isolation level serializable;

查询MySql当前的事物隔离等级用下面语句:

select @@tx_isolation;
//或者
show variables like '%tx_isolation%'

SpringBoot事务实现的方式

1. @Transactional注解

配置在类上

@Service("menuService")
@Transactional(rollbackFor = Exception.class)
public class MenuServiceImpl implements MenuService {
}

配置在方法上(推荐):

public class MenuServiceImpl implements MenuService {
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public int insertMenuInfo(List<MenuDto> menuDtoList) {
    }
}

💡提示: 如果同时配置在类跟方法上面,那肯定是方法上面的覆盖类上的,推荐方法上的原因是因为粒度更细。

2. 全局事务管理器

package org.wjw.mt;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import org.aspectj.lang.annotation.Aspect;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionManager;
import org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource;
import org.springframework.transaction.interceptor.RollbackRuleAttribute;
import org.springframework.transaction.interceptor.RuleBasedTransactionAttribute;
import org.springframework.transaction.interceptor.TransactionAttribute;
import org.springframework.transaction.interceptor.TransactionInterceptor;

/**
 * 全局事务管理器 <p/>
 * 注意: 1. 要在启动类里面引入注解@EnableTransactionManagement <p/>
 *       2. 尽量不要再使用@Transactional注解,如果要使用@Transactional注解,推荐配置在方法上,粒度细 <p/>
 *       3. 在使用全局事务的时候,方法命名一定要在下面的规范列表中,切勿出现奇葩命名 <p/>
 * @author White Stone
 *
 * 2021年5月21日
 */
@Aspect
@Configuration
public class TransactionalAopConfig {
  /**
   * 配置方法过期时间,如果是-1表时永不超时
   */
  private final static int METHOD_TIME_OUT = 5*1000;

  /**
   * 配置切入点表达式
   */
  private static final String POINTCUT_EXPRESSION = "execution(* org.wjw.mt.service..*.*(..))";

  /**
   * 容器注入的事务管理器
   */
  @Autowired
  private TransactionManager transactionManager;

  @Bean
  public TransactionInterceptor txAdvice() {
    //只读事务,不做更新操作
    RuleBasedTransactionAttribute readOnly = new RuleBasedTransactionAttribute();
    readOnly.setReadOnly(true);
    readOnly.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED);
    
    //当前存在事务就使用当前事务,当前不存在事务就创建一个新的事务
    RuleBasedTransactionAttribute required = new RuleBasedTransactionAttribute();
    //抛出异常后执行切点回滚,你可以更换异常的类型
    required.setRollbackRules(Collections.singletonList(new RollbackRuleAttribute(Exception.class)));
    //PROPAGATION_REQUIRED:事务隔离性为1,若当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认值
    required.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
    //设置事务失效时间,如果超过5秒,则回滚事务
    required.setTimeout(METHOD_TIME_OUT);
    
    Map<String, TransactionAttribute> attributesMap = new HashMap<>(30);
    //设置增删改上传等使用事务
    attributesMap.put("save*", required);
    attributesMap.put("remove*", required);
    attributesMap.put("update*", required);
    attributesMap.put("batch*", required);
    attributesMap.put("clear*", required);
    attributesMap.put("add*", required);
    attributesMap.put("append*", required);
    attributesMap.put("modify*", required);
    attributesMap.put("edit*", required);
    attributesMap.put("insert*", required);
    attributesMap.put("delete*", required);
    attributesMap.put("do*", required);
    attributesMap.put("create*", required);
    attributesMap.put("import*", required);
    //查询开启只读
    attributesMap.put("select*", readOnly);
    attributesMap.put("get*", readOnly);
    attributesMap.put("valid*", readOnly);
    attributesMap.put("list*", readOnly);
    attributesMap.put("count*", readOnly);
    attributesMap.put("find*", readOnly);
    attributesMap.put("load*", readOnly);
    attributesMap.put("search*", readOnly);

    //事务管理规则,声明具备事务管理的方法名
    NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
    source.setNameMap(attributesMap);
    return new TransactionInterceptor(transactionManager, source);
  }

  /**
   * 设置切面=切点pointcut+通知TxAdvice
   */
  @Bean
  public Advisor txAdviceAdvisor() {
    //声明切点的面:切面就是通知和切入点的结合。通知和切入点共同定义了关于切面的全部内容——它的功能、在何时和何地完成其功能
    AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
    //声明和设置需要拦截的方法,用切点语言描写
    pointcut.setExpression(POINTCUT_EXPRESSION);

    //设置切面=切点pointcut+通知TxAdvice
    return new DefaultPointcutAdvisor(pointcut, txAdvice());
  }

}

💡提示: 可以根据自己的需求更改attributesMap的内容等

注意点:

  1. 事务使用之前,要在启动类里面引入注解*@EnableTransactionManagement*
  2. 如果要使用*@Transactional*注解,推荐配置在方法上,粒度细
  3. 实际项目中还是推荐全局事务管理的,就怕有同事不写注解
  4. 使用全局事务的时候,方法命名一定要在上述规范中,切勿出现奇葩命名
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
在MySQL,时间类型有多种,包括DATETIME、DATE、TIME、TIMESTAMP等,不同的时间类型在Java的转换方式也略有不同。 1. DATETIME类型 在Java,可以使用java.sql.Timestamp类型来表示DATETIME类型。在通过JDBC从MySQL读取DATETIME类型的值时,可以使用ResultSet类的getTimestamp方法获取java.sql.Timestamp类型的值: ```java ResultSet rs = stmt.executeQuery("SELECT datetime_column FROM table"); while (rs.next()) { Timestamp datetime = rs.getTimestamp("datetime_column"); // ... } ``` 在将java.sql.Timestamp类型的值写入到MySQL的DATETIME类型的字段时,可以使用PreparedStatement类的setTimestamp方法: ```java PreparedStatement pstmt = conn.prepareStatement("INSERT INTO table (datetime_column) VALUES (?)"); Timestamp datetime = new Timestamp(System.currentTimeMillis()); pstmt.setTimestamp(1, datetime); pstmt.executeUpdate(); ``` 2. DATE类型 在Java,可以使用java.sql.Date类型来表示DATE类型。在通过JDBC从MySQL读取DATE类型的值时,可以使用ResultSet类的getDate方法获取java.sql.Date类型的值: ```java ResultSet rs = stmt.executeQuery("SELECT date_column FROM table"); while (rs.next()) { Date date = rs.getDate("date_column"); // ... } ``` 在将java.sql.Date类型的值写入到MySQL的DATE类型的字段时,可以使用PreparedStatement类的setDate方法: ```java PreparedStatement pstmt = conn.prepareStatement("INSERT INTO table (date_column) VALUES (?)"); Date date = new Date(System.currentTimeMillis()); pstmt.setDate(1, date); pstmt.executeUpdate(); ``` 3. TIME类型 在Java,可以使用java.sql.Time类型来表示TIME类型。在通过JDBC从MySQL读取TIME类型的值时,可以使用ResultSet类的getTime方法获取java.sql.Time类型的值: ```java ResultSet rs = stmt.executeQuery("SELECT time_column FROM table"); while (rs.next()) { Time time = rs.getTime("time_column"); // ... } ``` 在将java.sql.Time类型的值写入到MySQL的TIME类型的字段时,可以使用PreparedStatement类的setTime方法: ```java PreparedStatement pstmt = conn.prepareStatement("INSERT INTO table (time_column) VALUES (?)"); Time time = new Time(System.currentTimeMillis()); pstmt.setTime(1, time); pstmt.executeUpdate(); ``` 4. TIMESTAMP类型 在Java,可以使用java.sql.Timestamp类型来表示TIMESTAMP类型。在通过JDBC从MySQL读取TIMESTAMP类型的值时,可以使用ResultSet类的getTimestamp方法获取java.sql.Timestamp类型的值: ```java ResultSet rs = stmt.executeQuery("SELECT timestamp_column FROM table"); while (rs.next()) { Timestamp timestamp = rs.getTimestamp("timestamp_column"); // ... } ``` 在将java.sql.Timestamp类型的值写入到MySQL的TIMESTAMP类型的字段时,可以使用PreparedStatement类的setTimestamp方法: ```java PreparedStatement pstmt = conn.prepareStatement("INSERT INTO table (timestamp_column) VALUES (?)"); Timestamp timestamp = new Timestamp(System.currentTimeMillis()); pstmt.setTimestamp(1, timestamp); pstmt.executeUpdate(); ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱游泳的老白

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值