ibatis 生成 generatedkey mysql_Mybatis3.3.x技术内幕(十四):Mybatis之KeyGenerator

论坛 期权论坛 编程之家     
选择匿名的用户   2021-6-2 17:35   1994   0

在Mybatis中,执行insert操作时,如果我们希望返回数据库生成的自增主键值,那么就需要使用到KeyGenerator对象。

需要注意的是,KeyGenerator的作用,是返回数据库生成的自增主键值,而不是生成数据库的自增主键值。返回的主键值放到哪儿呢?放到parameter object的主键属性上。

下面看看其接口定义。

public interface KeyGenerator {

void processBefore(Executor executor, MappedStatement ms, Statement stmt, Object parameter);

void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter);

}

接口定义还是比较简单的,就是在insert前、insert后,策略处理主键值。

475861e4616eafee30ba605eb3ed78f6.png

(Made In IntelliJ IDEA IDE)

Jdbc3KeyGenerator:用于处理数据库支持自增主键的情况,如MySQL的auto_increment。

NoKeyGenerator:空实现,不需要处理主键。

SelectKeyGenerator:用于处理数据库不支持自增主键的情况,比如Oracle的sequence序列。

上面都比较泛泛而谈,我们来点实际的,看看它们都是如何工作的。

1. JDBC实现insert后,返回自增主键值的原理

Class.forName("com.mysql.jdbc.Driver");

Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "root", "123");

conn.setAutoCommit(false);

PreparedStatement pstm = conn.prepareStatement("insert into students(name, email) values(?, ?)",

Statement.RETURN_GENERATED_KEYS);

pstm.setString(1, "name1");

pstm.setString(2, "email1");

pstm.addBatch();

pstm.setString(1, "name2");

pstm.setString(2, "email2");

pstm.addBatch();

pstm.executeBatch();

// 返回自增主键值

ResultSet rs = pstm.getGeneratedKeys();

while (rs.next()) {

Object value = rs.getObject(1);

System.out.println(value);

}

conn.commit();

rs.close();

pstm.close();

conn.close();

output:

246

247

以上代码,仅作为演示使用。Mybatis是对JDBC的封装,其Jdbc3KeyGenerator类,就是使用上面的原理,来返回数据库生成的主键值的。

2. Jdbc3KeyGenerator源码解读

public class Jdbc3KeyGenerator implements KeyGenerator {

@Override

public void processBefore(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {

// do nothing

}

@Override

public void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {

processBatch(ms, stmt, getParameters(parameter));

}

public void processBatch(MappedStatement ms, Statement stmt, Collection parameters) {

ResultSet rs = null;

try {

// 获得返回的主键值结果集

rs = stmt.getGeneratedKeys();

final Configuration configuration = ms.getConfiguration();

final TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();

final String[] keyProperties = ms.getKeyProperties();

final ResultSetMetaData rsmd = rs.getMetaData();

TypeHandler>[] typeHandlers = null;

if (keyProperties != null && rsmd.getColumnCount() >= keyProperties.length) {

// 给参数object对象的属性赋主键值(批量插入,可能是多个)

for (Object parameter : parameters) {

// there should be one row for each statement (also one for each parameter)

if (!rs.next()) {

break;

}

final MetaObject metaParam = configuration.newMetaObject(parameter);

if (typeHandlers == null) {

typeHandlers = getTypeHandlers(typeHandlerRegistry, metaParam, keyProperties, rsmd);

}

// 赋值

populateKeys(rs, metaParam, keyProperties, typeHandlers);

}

}

} catch (Exception e) {

throw new ExecutorException("Error getting generated key or setting result to parameter object. Cause: " + e, e);

} finally {

if (rs != null) {

try {

rs.close();

} catch (Exception e) {

// ignore

}

}

}

}

private void populateKeys(ResultSet rs, MetaObject metaParam, String[] keyProperties, TypeHandler>[] typeHandlers) throws SQLException {

// 主键字段,可能是多个(一般情况下,是一个)

for (int i = 0; i < keyProperties.length; i++) {

TypeHandler> th = typeHandlers[i];

if (th != null) {

Object value = th.getResult(rs,此时,如果你考虑性能的话,可以使用BatchExecutor来完成,当然了,其他的Executor也是可以的。

如果文章就像上面这样写,那么就完全失去了写文章的价值,上面的for循环,谁都懂这么操作可以实现,但是,很多人想要的并不是这个例子,而是另外一种批量插入操作,返回主键id列表。那么,看第8条。

8. Mybatis批量插入,返回主键id列表为null

INSERT INTO

STUDENTS(STUD_ID, NAME, EMAIL, DOB, PHONE)

VALUES

(#{item.studId},#{item.name},#{item.email},#{item.dob}, #{item.phone})

很多同学,包括开源中国社区,都遇到使用上面的批量insert操作,返回的主键id列表是null的问题,很多人得出结论:Mybatis不支持这种形式的批量插入并返回主键id列表。真是这样吗?

我必须明确的跟大家说,Mybatis是支持上述形式的批量插入,且可以正确返回主键id列表的。之所以返回null值,是Mybatis框架的一个bug,下一篇将具体讲述产生这个bug的原因,以及如何修复它。

版权提示:文章出自开源中国社区,若对文章感兴趣,可关注我的开源中国社区博客(http://my.oschina.net/zudajun)。(经过网络爬虫或转载的文章,经常丢失流程图、时序图,格式错乱等,还是看原版的比较好)

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:3875789
帖子:775174
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP