mybatis_plus

mybatis_plus

(1)测试

自动拼接sql语句

Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3b48e183] was not registered for synchronization because synchronization is not active
2021-04-19 16:18:05.070  INFO 3268 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2021-04-19 16:18:05.474  INFO 3268 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
JDBC Connection [HikariProxyConnection@526874139 wrapping com.mysql.jdbc.JDBC4Connection@5a034157] will not be managed by Spring
==>  Preparing: UPDATE user SET name=?, age=? WHERE id=?
==> Parameters: 小天(String), 18(Integer), 7(Long)
<==    Updates: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3b48e183]

(2)自动填充

创建时间,修改时间 自动化完成,不需要手动更新

阿里巴巴开发手册:gmt_create,gmt_modified

几乎所有的表都要配置,自动化

数据库级别

1)在表中新增字段(需要设置timestamp类型)

create_time,create_user

private Date createTime;
private Date updateTime;

代码级别

(1)修改数据库

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i5LNb4AY-1623747912237)(C:\Users\root\AppData\Roaming\Typora\typora-user-images\image-20210419164641845.png)]

(2)添加注解

package com.example.pojo;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class User {
    @TableId(type = IdType.AUTO)
    private Long id;
    private String name;
    private int age;
    private String email;
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;
    //开始的时候两个字段都要有内容
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;


}

(3)编写处理器来处理这个注解

package com.example.handler;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;

import java.util.Date;

//加到ioc容器中
@Component
@Slf4j
public class MyMetaObjectHandler implements MetaObjectHandler {
    //插入时填充策略
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("start insert fill...");
        // default MetaObjectHandler setFieldValByName(String fieldName, Object fieldVal, MetaObject metaObject)
        this.setFieldValByName("createTime", new Date(), metaObject);
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("start update fill...");
        this.setFieldValByName("updateTime", new Date(), metaObject);

    }
}

(4)结果

Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6a6f6c7e] was not registered for synchronization because synchronization is not active
2021-04-19 17:01:25.588  INFO 8220 --- [           main] com.example.handler.MyMetaObjectHandler  : start update fill...
2021-04-19 17:01:25.597  INFO 8220 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2021-04-19 17:01:25.925  INFO 8220 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
JDBC Connection [HikariProxyConnection@1679401185 wrapping com.mysql.jdbc.JDBC4Connection@280d4882] will not be managed by Spring
==>  Preparing: UPDATE user SET name=?, age=?, update_time=? WHERE id=?
==> Parameters: 李继(String), 68(Integer), 2021-04-19 17:01:25.588(Timestamp), 7(Long)
<==    Updates: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6a6f6c7e]
2021-04-1

(5)插入

==> Preparing: INSERT INTO user ( name, age, create_time, update_time ) VALUES ( ?, ?, ?, ? )
> Parameters: 曹钦(String), 23(Integer), 2021-04-19 17:04:19.321(Timestamp), null
<
Updates: 1

mysql 锁 CAS

乐观锁

他总认为不会出现问题,无论干什么都不会加锁,出了问题再次更新值测试

悲观锁

他总是认为会出现问题,无论干什么都会上锁再去操作

当要更新一条记录的时候,希望这条记录没有被别人更新
乐观锁实现方式:

  • 取出记录时,获取当前version
  • 更新时,带上这个version
  • 执行更新时, set version = newVersion where version = oldVersion
  • 如果version不对,就更新失败

测试MP乐观锁插件

(1)添加数据库字段

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3ODLilEt-1623747912239)(C:\Users\root\AppData\Roaming\Typora\typora-user-images\image-20210419173035953.png)]

(2)增加数据库字段到pojo

@Version
private Integer version;

(3)注册组件

package com.example.config;

import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
//自动管理事务,默认管理了
//
@MapperScan("com.example.mapper")
@EnableTransactionManagement
public class MybatisPlusConfig {
    //注册
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return mybatisPlusInterceptor;
    }
}

(4)测试

成功

//测试乐观锁
//成功
@Test
public void success() {
    //查询用户信息
    User user = userMapper.selectById(1);
    //单线程修改
    user.setName("zrm");
    user.setEmail("1677");
    int i = userMapper.updateById(user);
    System.out.println(i);
}JDBC Connection [HikariProxyConnection@805536380 wrapping com.mysql.jdbc.JDBC4Connection@38f77cd9] will not be managed by Spring
==>  Preparing: UPDATE user SET name=?, age=?, email=?, update_time=?, version=? WHERE id=? AND version=?
==> Parameters: zrm(String), 68(Integer), 1677(String), 2021-04-19 17:43:02.346(Timestamp), 2(Integer), 1(Long), 1(Integer)
<==    Updates: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6aa3bfc]

失败

//失败(多线程会失败)
@Test
public void fail() {
    User user1 = userMapper.selectById(1);
    //单线程修改
    user1.setName("于洪111");
    user1.setEmail("28999111");
    //模拟另外一个线程插队操作

    User user2 = userMapper.selectById(1);
    //单线程修改
    user2.setName("于洪222");
    user2.setEmail("28999222");
    //另一个线程抢先完成更新
    userMapper.updateById(user2);

    //如果没有乐观锁会覆盖抢完更新的值
    //可以尝试自旋锁来尝试多次提交
    userMapper.updateById(user1);
}
<think>好的,我现在要帮用户分析MyBatisSqlSession日志,特别是JDBC连接同步行为。首先,我需要回顾用户提供的引用内容,确保理解相关机制。 用户引用了MyBatis的Transaction对象,它封装了JDBC Connection。JdbcTransaction类中的commit和rollback方法会操作底层的Connection对象[^1]。这说明MyBatis的事务管理是通过这个Transaction对象来处理连接的提交和回滚的。 接下来,引用[2]提到TransactionSynchronizationManager的bindResource方法,用于将DataSource和ConnectionHolder绑定到当前线程。这确保了同一线程在处理多个连接池时能正确获取对应的Connection。这里关键点是线程与连接池共同作为key,保证连接的唯一性。这涉及到Spring的事务同步管理,可能与MyBatis集成Spring时的行为有关。 引用[3]中的代码示例展示了在Service层如何通过AOP代理实现事务管理。用户通过AopContext.currentProxy()调用同一个类中的事务方法,确保@Transactional生效。这说明用户可能在使用Spring管理事务,并且需要方法间的事务传播。 现在,用户的问题是关于SqlSession日志分析和JDBC连接的同步行为。需要结合MyBatis的事务管理和Spring的同步机制来分析日志。 首先,SqlSessionMyBatis中代表一次数据库会话,每个SqlSession会关联一个Executor,而Executor负责具体的SQL执行。根据引用[1],Executor与SqlSession的关系密切,事务的管理由Transaction对象处理。 当在Spring中使用MyBatis时,通常通过SqlSessionTemplate管理SqlSession的生命周期,并且与Spring的事务管理整合。TransactionSynchronizationManager在这里起到关键作用,绑定资源到线程,确保同一事务中的操作使用相同的Connection。 在日志分析中,用户可能会看到与连接获取、提交、回滚相关的日志条目。例如,当开启事务时,MyBatis会从数据源获取连接,并可能通过TransactionSynchronizationManager绑定到当前线程。此时,日志中可能出现类似“Committing JDBC Connection”或“Rolling back”的信息,这些来自JdbcTransaction的commit和rollback方法。 另外,在引用[3]的示例中,非事务方法调用事务方法时,使用AOP代理确保事务生效。这种情况下,日志中可能会显示连接的获取和释放,以及事务的边界。例如,当进入updateTest方法时,Spring会开启事务,获取Connection,并绑定到当前线程。执行更新操作后,事务提交,连接释放。 用户需要关注的日志点可能包括: 1. 连接的打开和关闭时间点,是否复用。 2. 事务的提交或回滚记录,判断事务是否正确处理。 3. 是否有连接未正确释放导致的泄漏,比如未关闭的SqlSession。 此外,如果启用了DEBUG级别的日志,MyBatis和Spring会输出更详细的信息,如连接的哈希码,帮助跟踪同一个连接在不同操作中的使用情况。例如,在JdbcTransaction的commit方法中,日志会打印“Committing JDBC Connection [connection对象]”,通过这个可以确认同一连接在多个操作中被使用,表明事务同步正常。 如果用户发现连接未按预期同步,可能需要检查事务管理配置,例如是否遗漏了@Transactional注解,或者传播行为设置不正确。例如,REQUIRED传播行为会让方法加入现有事务,而REQUIRES_NEW会创建新事务,导致不同的连接获取。 总结来说,分析日志时需要关注连接的生命周期、事务的边界以及线程绑定的情况,结合MyBatis和Spring的机制来理解JDBC连接的行为。同时,确保日志级别足够详细,能够捕捉到关键的操作步骤,帮助定位问题。</think>### MyBatis SqlSession日志分析与JDBC连接同步行为解析 #### 一、核心机制解析 1. **SqlSession与连接绑定** - SqlSessionMyBatis操作数据库的核心入口,每个SqlSession对应一个数据库连接$^{[^1]}$ - 通过`TransactionSynchronizationManager.bindResource()`实现线程级连接绑定,键为`DataSource + ConnectionHolder`,确保同一线程内相同数据源使用唯一连接$^{[^2]}$ ```java // 典型日志输出示例 DEBUG o.a.ibatis.transaction.jdbc.JdbcTransaction - Opening JDBC Connection DEBUG org.mybatis.spring.SqlSessionUtils - Creating a new SqlSession ``` 2. **事务同步行为** - 事务开启时通过`JdbcTransaction.getConnection()`获取连接,若未绑定则创建新连接$^{}$ - Spring管理的连接会复用已绑定的资源,日志中可见`Fetching JDBC Connection from DataSource` #### 二、关键日志分析步骤 1. **识别连接生命周期** - 连接创建:`DEBUG JdbcTransaction - Opening JDBC Connection [HashCode]` - 连接提交:`DEBUG JdbcTransaction - Committing JDBC Connection [HashCode]` - 连接释放:`DEBUG SqlSessionUtils - Closing non transactional SqlSession` 2. **事务边界判定** - 事务开启:`DEBUG TransactionInterceptor - Getting transaction for [methodName]` - 事务提交:`DEBUG DataSourceTransactionManager - Initiating transaction commit` - 异常回滚:`WARN TransactionInterceptor - Application exception overridden by rollback exception` #### 三、典型场景分析 1. **嵌套事务场景** ```log DEBUG DataSourceUtils - Fetching JDBC Connection from DataSource DEBUG TransactionSynchronizationManager - Bound value [org.springframework.jdbc.datasource.ConnectionHolder] for key [HikariDataSource] DEBUG JdbcTransaction - Using connection [com.mysql.cj.jdbc.ConnectionImpl@5e3a8624] ``` 表示连接被成功绑定并复用 2. **连接未同步异常** ```log WARN SqlSessionUtils - SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession] was not registered for synchronization because synchronization is not active ``` 表示当前操作未在事务管理范围内,需检查`@Transactional`注解或事务传播配置$^{[^3]}$ #### 四、调试建议 1. 启用DEBUG级别日志配置: ```properties logging.level.org.mybatis=DEBUG logging.level.org.springframework.jdbc=DEBUG logging.level.org.springframework.transaction=DEBUG ``` 2. 关注连接哈希值一致性,判断是否实现正确同步: ```log DEBUG JdbcTransaction - Committing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@5e3a8624] DEBUG JdbcTransaction - Rolling back JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@5e3a8624] ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值