mybatis-3.4.6 自增主键
2020-07-24 本文已影响0人
晴天哥_王志
系列
- mybatis-3.4.6 配置介绍
- mybatis-3.4.6 顶层配置解析
- mybatis-3.4.6 子配置解析
- mybatis-3.4.6 mapper解析
- mybatis-3.4.6 SQL执行流程
- mybatis-3.4.6 SqlSession执行过程
- mybatis-3.4.6 缓存介绍
- mybatis-3.4.6 自增主键
- mybatis-3.4.6 foreach 自增主键
开篇
-
这个系列是基于mybatis-3.4.6版本的源码解析,这篇文章主要分析mybatis的主键生成的逻辑。
-
这篇文章会阐述JDBC本身获取自增主键的原理和mybatis处理自增主键的逻辑。
-
mybatis针对自增主键的处理是建立在JDBC的Statement的getGeneratedKeys基础上,所以本质还是得理解JDBC针对自增主键的处理逻辑。
JDBC自增主键
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();
- PreparedStatement在executeBatch后通过getGeneratedKeys来返回生成的主键。
mybatis自增主键
<insert id="addUser" parameterType="cn.edu.example.entity.ImcUser" useGeneratedKeys="true" keyProperty="userId">
INSERT INTO imc_user (`user_nick`) VALUES (#{userNick})
</insert>
- mybatis的自增主键需要的配置如上所示,核心关键字包括useGeneratedKeys和keyProperty。
DefaultSqlSession
public class DefaultSqlSession implements SqlSession {
@Override
public int insert(String statement, Object parameter) {
return update(statement, parameter);
}
@Override
public int update(String statement, Object parameter) {
try {
dirty = true;
MappedStatement ms = configuration.getMappedStatement(statement);
// 通过CachingExecutor执行update操作
return executor.update(ms, wrapCollection(parameter));
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error updating database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
}
- mybaits的insert/update都是通过DefaultSqlSession的update来实现的。
- DefaultSqlSession的update执行CachingExecutor的update操作。
CachingExecutor
public class CachingExecutor implements Executor {
public int update(MappedStatement ms, Object parameterObject) throws SQLException {
flushCacheIfRequired(ms);
return delegate.update(ms, parameterObject);
}
- CachingExecutor调用SimpleExecutor的update操作执行逻辑。
SimpleExecutor
public abstract class BaseExecutor implements Executor {
@Override
public int update(MappedStatement ms, Object parameter) throws SQLException {
ErrorContext.instance().resource(ms.getResource()).activity("executing an update").object(ms.getId());
if (closed) {
throw new ExecutorException("Executor was closed.");
}
clearLocalCache();
return doUpdate(ms, parameter);
}
}
public class SimpleExecutor extends BaseExecutor {
public SimpleExecutor(Configuration configuration, Transaction transaction) {
super(configuration, transaction);
}
@Override
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
Statement stmt = null;
try {
Configuration configuration = ms.getConfiguration();
// handler为PreparedStatementHandler
StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
// 生成Statement对象
stmt = prepareStatement(handler, ms.getStatementLog());
// 执行Statement的操作
return handler.update(stmt);
} finally {
closeStatement(stmt);
}
}
}
- SimpleExecutor的doUpdate负责执行真正的update操作。
- 由PreparedStatementHandler来处理真正的update操作。
PreparedStatementHandler
public class PreparedStatementHandler extends BaseStatementHandler {
public PreparedStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);
}
@Override
public int update(Statement statement) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
// 执行PreparedStatement的操作
ps.execute();
// 获取影响的行数
int rows = ps.getUpdateCount();
// 获取KeyGenerator对象,处理自增主键
Object parameterObject = boundSql.getParameterObject();
// mysql使用Jdbc3KeyGenerator来进行处理
KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
keyGenerator.processAfter(executor, mappedStatement, ps, parameterObject);
return rows;
}
- 本质上和mysql的交互都是由PreparedStatement的execute来实现的。
Jdbc3KeyGenerator
public class Jdbc3KeyGenerator implements KeyGenerator {
public static final Jdbc3KeyGenerator INSTANCE = new Jdbc3KeyGenerator();
@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<Object> parameters) {
ResultSet rs = null;
try {
// 获取自增主键的ResultSet集合
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) {
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) {
} finally {
}
}
private void populateKeys(ResultSet rs, MetaObject metaParam, String[] keyProperties, TypeHandler<?>[] typeHandlers) throws SQLException {
for (int i = 0; i < keyProperties.length; i++) {
String property = keyProperties[i];
TypeHandler<?> th = typeHandlers[i];
if (th != null) {
Object value = th.getResult(rs, i + 1);
metaParam.setValue(property, value);
}
}
}
}
- Jdbc3KeyGenerator在mybatis中负责处理mysql的自增主键。
- PreparedStatement的getGeneratedKeys负责获取自增的key。
- populateKeys根据不同数据类型对应的handler完成数据的处理。