官网链接
英文官网:https://mybatis.org/mybatis-3/
Mybatis中自动生成主键
<insert id="" parameterType="" keyColumn="id" keyProperty="id" useGeneratedKeys="true">
-
useGeneratedKeys=true表示使用数据库自动增长的主键
-
keyProperty设置自增主键返回字段(用户在插入数据之后获取相应主键)
-
keyColumn用于指定数据库table中的主键
这是三个属性同时使用时,则可以使用数据库中自增长的主键,并且可以将主键的值返回给keyProperty中写好的字段
Mybatis批处理
public class MybatisBatchUtils {
/**
* 每次处理1000条
*/
private static final int BATCH_SIZE = 1000;
@Resource
private SqlSessionFactory sqlSessionFactory;
/**
* 批量处理修改或者插入
*
* @param data 需要被处理的数据
* @param mapperClass Mybatis的Mapper类
* @param function 自定义处理逻辑 (函数式接口)
* @return int 影响的总行数
*/
public <T,U,R>int batchUpdateOrInsert(List<T> data, Class<U> mapperClass, BiFunction<T,U,R> function)
{
int i = 1;
SqlSession batchSqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
try {
U mapper = batchSqlSession.getMapper(mapperClass);
int size = data.size();
for (T element : data) {
// 更新:mapper.update(element);
// 插入:mapper.insert(element)
function.apply(element,mapper);
if ((i % BATCH_SIZE == 0) || i == size) {
batchSqlSession.flushStatements();
}
i++;
}
// 非事务环境下强制commit,事务情况下该commit相当于无效
batchSqlSession.commit(!TransactionSynchronizationManager.isSynchronizationActive());
} catch (Exception e) {
batchSqlSession.rollback();
throw new CustomException(e);
} finally {
batchSqlSession.close();
}
return i - 1;
}
}
使用案例:batchUtils.batchUpdateOrInsert(数据集合, xxxxx.class, (item, mapper实例对象) -> mapper实例对象.insert方法(item)); 函数式接口可以用Lambda的方式实现具体逻辑
如果方法上用了@Transactional注解,由于在 Spring 集成的情况下,事务连接由 Spring 管理(SpringManagedTransaction),所以这里不需要手动关闭 sqlSession,在这里手动提交(commit)或者回滚(rollback)也是无效的。如果没有使用事务注解,那就一步一步来,提交了再关闭。
PreparedStatement 预编译
- 预编译显式开启(在url中指定useServerPrepStmts=true),否则PreparedStatement不会向mysql发送预编译(Prepare命令)的请求;
- 每次向mysql发送预编译请求,不管之前有没有执行过此SQL语句,只要请求的命令是Prepare或Query,mysql就会重新编译一次SQL语句,并返回此链接当前唯一的Statement ID,后续执行SQL语句的时候,程序只需拿着Statement ID和参数就可以了;
- 当预编译的SQL语句有语法错误,则mysql的响应会携带错误信息,但此错误信息JDBC感知不到(或者说mysql-connetor-java.jar包里的实现将其忽略掉了),此时还会继续往下执行代码,当执行到executeXxx()方法时,由于没有Statement ID(所以就会将拼接完整的SQL语句值已经将占位符(?)替换掉再次发给mysql请求执行,此时mysql响应有语法错误,这时JDBC就会抛出语法错误异常),所以检查语法那一步实在mysql-server中做的(通过抓包可以看到);
- PreparedStatement对性能的提高是利用缓存实现的,需要显式开启(在url中指定cachePrepStmts=true),此缓存是mysql-connetor-java.jar包里实现的(非mysql-server中的缓存),缓存的key是完整的sql语句,value是PreparedStatement对象。放入缓存是PreparedStatement.close()触发的,所以只要缓存PreparedStatement对象没有关闭,你不管调用多少次connection.prapareStatement(sql)对相同的sql语句进行预编译,都会将预编译的请求发给mysql,mysql也会对每一个sql语句不管是否相同进行预编译,并生成一个唯一的Statement ID并返回;
- 缓存是针对链接的,每个链接都是独立的,不共享缓存 。
where标签
https://blog.youkuaiyun.com/wo541075754/article/details/123244510
这里就涉及到where
标签的两个特性:
- 第一,只有if标签有内容的情况下才会插入
where
子句; - 第二,若子句的开通为 “
AND
” 或 “OR
”,where
标签会将它替换去除;
但需要注意的是:where
标签只会 智能的去除(忽略)首个满足条件语句的前缀。所以建议在使用where
标签时,每个语句都最好写上 and 前缀或者 or 前缀。
trim标签
https://zhuanlan.zhihu.com/p/425922768
基本格式:
<trim prefix="" suffix="" suffixOverrides="" prefixOverrides=""></trim>
-
prefix:
-
- 表示在trim包裹的SQL语句前面添加的指定内容。
-
suffix:
-
- 表示在trim包裹的SQL末尾添加指定内容
-
prefixOverrides:
-
- 表示去掉(覆盖)trim包裹的SQL的指定首部内容
-
suffixOverrides:
-
- 表示去掉(覆盖)trim包裹的SQL的指定尾部内容