测试准备
添加mybatis-config.xml全局配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 引入外部资源配置文件 -->
<properties resource="jdbc.properties"/>
<settings>
<!-- 开启驼峰自动映射 -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
<!-- 设置二级缓存开关 默认开启 -->
<setting name="cacheEnabled" value="true"/>
<!-- 延迟加载的开关 默认关闭-->
<setting name="lazyLoadingEnabled" value="true"/>
<!--
true启用时,当延迟加载开启时访问对象中一个懒对象属性时,将完全加载这个对象的所有懒对象属性。
false,当延迟加载时,按需加载对象属性(即访问对象中一个懒对象属性,不会加载对象中其他的懒对象属性)。
默认为false
-->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
<typeAliases>
<!-- 别名 type 指定java对象类型 alias 别名名称 -->
<typeAlias type="com.laravelshao.learning.mybatis.pojo.User" alias="User"/>
<!-- 指定扫描包 Mybatis会将该包下所有类都生成别名(别名首字母不区分大小写) -->
<package name="com.laravelshao.learning.mybatis.pojo"/>
</typeAliases>
<!-- 配置分页插件 -->
<plugins>
<plugin interceptor="com.github.pagehelper.PageHelper">
<property name="dialect" value="mysql"/>
<!-- 使用RowBounds分页是否进行count查询 默认false-->
<property name="rowBoundsWithCount" value="true"/>
</plugin>
</plugins>
<!-- 配置环境 指定数据库连接信息 -->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<!-- 引入mapper配置文件 -->
<!--<mapper resource="com/laravelshao/learning/mybatis/mapper/UserMapper.xml"/>-->
<!-- 配置mapper接口扫描包 -->
<package name="com.laravelshao.learning.mybatis.mapper"/>
</mappers>
</configuration>
jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/mybatis?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
jdbc.username=root
jdbc.password=123456
添加实体类
public class User implements Serializable {
private Long id;
// 用户名
private String userName;
// 密码
private String password;
// 姓名
private String name;
// 年龄
private Integer age;
// 性别 1 男性 2 女性
private Integer sex;
// 出生日期
private Date birthday;
// 创建时间
private Date created;
// 更新时间
private Date updated;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Integer getSex() {
return sex;
}
public void setSex(Integer sex) {
this.sex = sex;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public Date getCreated() {
return created;
}
public void setCreated(Date created) {
this.created = created;
}
public Date getUpdated() {
return updated;
}
public void setUpdated(Date updated) {
this.updated = updated;
}
@Override
public String toString() {
return "User [id=" + id + ", userName=" + userName + ", password=" + password + ", name=" + name
+ ", age=" + age + ", sex=" + sex + ", birthday=" + birthday + ", created=" + created
+ ", updated=" + updated + "]";
}
}
添加mapper接口
public interface UserMapper {
/**
* 根据id查询用户信息
*
* @param id
* @return
*/
User queryUserById(Long id);
/**
* 查询所有用户数据
*
* @return
*/
List<User> queryAll();
/**
* 新增用户信息
*
* @param user
*/
void saveUser(User user);
/**
* 更新用户信息
*
* @param user
*/
void updateUser(User user);
/**
* 根据id删除用户信息
*
* @param id
*/
void deleteUserById(Long id);
}
添加mapper映射文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace 命名空间(保持唯一) 如需mybatis生成mapper动态代理类 则必须使用mapper接口全路径 -->
<mapper namespace="com.laravelshao.learning.mybatis.mapper.UserMapper">
<!--
id:ResultMap唯一标识
type:结果集映射的java对象全路径或者别名
autoMapping:是否自动映射没有映射关系的属性和字段 默认开启
-->
<resultMap id="userResultMap" type="User" autoMapping="true">
<!-- column:字段名 property:属性名 -->
<id column="id" property="id"/>
<result column="user_name" property="userName"/>
</resultMap>
<!-- 根据id查询用户信息 -->
<!--<select id="queryUserById" resultType="User">-->
<select id="queryUserById" resultMap="userResultMap">
SELECT * FROM tb_user WHERE id = #{id}
</select>
<!-- 查询所有用户数据 -->
<select id="queryAll" resultType="com.laravelshao.learning.mybatis.pojo.User">
SELECT * FROM tb_user
</select>
<!-- 新增用户信息 -->
<insert id="saveUser" parameterType="com.laravelshao.learning.mybatis.pojo.User">
INSERT INTO tb_user (
id,
user_name,
password,
name,
age,
sex,
birthday,
created,
updated
)
VALUES
(
NULL,
#{userName},
#{password},
#{name},
#{age},
#{sex},
#{birthday},
NOW(),
NOW()
);
</insert>
<!-- 更新用户信息 -->
<update id="updateUser" parameterType="com.laravelshao.learning.mybatis.pojo.User">
UPDATE tb_user
SET
user_name = #{userName},
password = #{password},
name = #{name},
age = #{age},
sex = #{sex},
birthday = #{birthday},
updated = NOW()
WHERE
id = #{id}
</update>
<!-- 根据id删除用户信息 -->
<delete id="deleteUserById" parameterType="java.lang.Long">
DELETE FROM tb_user WHERE id = #{id}
</delete>
</mapper>
添加测试方法
public class UserMapperTest {
private UserMapper userMapper;
SqlSession sqlSession = null;
SqlSessionFactory sqlSessionFactory = null;
@Before
public void setUp() throws Exception {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//openSession(boolean autoCommit) 设置事务是否自动提交
sqlSession = sqlSessionFactory.openSession(true);
// 获取动态代理实现类
this.userMapper = sqlSession.getMapper(UserMapper.class);
}
@Test
public void testQueryUserById() {
User user = userMapper.queryUserById(1L);
System.out.println(user);
}
@Test
public void testQueryAll() {
List<User> users = userMapper.queryAll();
for (User user : users) {
System.out.println(user);
}
}
@Test
public void testSaveUser() {
User user = new User();
user.setAge(20);
user.setBirthday(new Date());
user.setName("test_name_1");
user.setPassword("123456");
user.setSex(1);
user.setUserName("test_userName_1");
userMapper.saveUser(user);
}
@Test
public void testUpdateUser() {
User user = userMapper.queryUserById(2L);
user.setAge(30);
userMapper.updateUser(user);
}
@Test
public void testDeleteUserById() {
userMapper.deleteUserById(8L);
}
}
执行过程分析
SqlSession创建
SqlSession创建通过调用DefaultSqlSessionFactory的openSession方法进而调用openSessionFromDataSource方法
// DefaultSqlSessionFactory
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
DefaultSqlSession var8;
try {
Environment environment = this.configuration.getEnvironment(); // 从全局配置类configuration获取environment信息
TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment); // 获取事务工厂
// 创建新的事务
// 参数1:数据源 参数2:事务隔离级别 参数3:是否自动提交事务
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
Executor executor = this.configuration.newExecutor(tx, execType); // 创建执行器
var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
} catch (Exception var12) {
this.closeTransaction(tx);
throw ExceptionFactory.wrapException("Error opening session. Cause: " + var12, var12);
} finally {
ErrorContext.instance().reset();
}
return var8;
}
创建执行器
// Configuration
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
executorType = executorType == null ? this.defaultExecutorType : executorType;
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
Object executor;
// 根据执行器类型创建不同执行器
if (ExecutorType.BATCH == executorType) {
executor = new BatchExecutor(this, transaction);
} else if (ExecutorType.REUSE == executorType) {
executor = new ReuseExecutor(this, transaction);
} else {
executor = new SimpleExecutor(this, transaction);
}
if (this.cacheEnabled) {
executor = new CachingExecutor((Executor)executor);
}
Executor executor = (Executor)this.interceptorChain.pluginAll(executor);
return executor;
}
摘自mybatis官网
ExecutorType枚举类型定义了三个值:
• ExecutorType.SIMPLE:这个执行器类型不做特殊的事情。它为每个语句的执行创建一个新的预处理语句。
• ExecutorType.REUSE:这个执行器类型会复用预处理语句。
• ExecutorType.BATCH:这个执行器会批量执行所有更新语句,如果SELECT在它们中间执行,必要时请把它们区分开来以保证行为的易读性。
Executor定义了具体执行SQL方法
public interface Executor {
ResultHandler NO_RESULT_HANDLER = null;
int update(MappedStatement var1, Object var2) throws SQLException;
<E> List<E> query(MappedStatement var1, Object var2, RowBounds var3, ResultHandler var4, CacheKey var5, BoundSql var6) throws SQLException;
<E> List<E> query(MappedStatement var1, Object var2, RowBounds var3, ResultHandler var4) throws SQLException;
<E> Cursor<E> queryCursor(MappedStatement var1, Object var2, RowBounds var3) throws SQLException;
List<BatchResult> flushStatements() throws SQLException;
void commit(boolean var1) throws SQLException;
void rollback(boolean var1) throws SQLException;
CacheKey createCacheKey(MappedStatement var1, Object var2, RowBounds var3, BoundSql var4);
boolean isCached(MappedStatement var1, CacheKey var2);
void clearLocalCache();
void deferLoad(MappedStatement var1, MetaObject var2, String var3, CacheKey var4, Class<?> var5);
Transaction getTransaction();
void close(boolean var1);
boolean isClosed();
void setExecutorWrapper(Executor var1);
}
Mapper代理类创建
调用DefaultSqlSession的getMapper方法,进而调用MapperRegistry,最后调用MapperProxyFactory最终创建出mapper代理对象
// DefaultSqlSession
public <T> T getMapper(Class<T> type) {
return this.configuration.getMapper(type, this);
}
// Configuration
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
return this.mapperRegistry.getMapper(type, sqlSession);
}
// MapperRegistry
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
} else {
try {
return mapperProxyFactory.newInstance(sqlSession); // 交给mapper代理工厂创建对象
} catch (Exception var5) {
throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
}
}
}
Mapper代理工厂创建代理类对象
// MapperProxyFactory
public T newInstance(SqlSession sqlSession) {
MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
return this.newInstance(mapperProxy);
}
protected T newInstance(MapperProxy<T> mapperProxy) {
// JDK动态代理生成mapper代理类对象
return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy);
}
SQL执行流程
查询流程分析
这里以方法queryAll为例分析SQL执行过程
@Test
public void testQueryAll() {
List<User> users = userMapper.queryAll();
for (User user : users) {
System.out.println(user);
}
}
调用代理类的invoke方法
// MapperProxy
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
}
if (this.isDefaultMethod(method)) {
return this.invokeDefaultMethod(proxy, method, args);
}
} catch (Throwable var5) {
throw ExceptionUtil.unwrapThrowable(var5);
}
MapperMethod mapperMethod = this.cachedMapperMethod(method);
return mapperMethod.execute(this.sqlSession, args); // 执行mapper方法
}
执行具体方法
// MapperMethod
public Object execute(SqlSession sqlSession, Object[] args) {
Object param;
Object result;
switch(this.command.getType()) { // 根据方法类型执行不同方法
case INSERT:
param = this.method.convertArgsToSqlCommandParam(args);
result = this.rowCountResult(sqlSession.insert(this.command.getName(), param));
break;
case UPDATE:
param = this.method.convertArgsToSqlCommandParam(args);
result = this.rowCountResult(sqlSession.update(this.command.getName(), param));
break;
case DELETE:
param = this.method.convertArgsToSqlCommandParam(args);
result = this.rowCountResult(sqlSession.delete(this.command.getName(), param));
break;
case SELECT:
if (this.method.returnsVoid() && this.method.hasResultHandler()) {
this.executeWithResultHandler(sqlSession, args);
result = null;
} else if (this.method.returnsMany()) {
result = this.executeForMany(sqlSession, args);
} else if (this.method.returnsMap()) {
result = this.executeForMap(sqlSession, args);
} else if (this.method.returnsCursor()) {
result = this.executeForCursor(sqlSession, args);
} else {
param = this.method.convertArgsToSqlCommandParam(args);
result = sqlSession.selectOne(this.command.getName(), param);
}
break;
case FLUSH:
result = sqlSession.flushStatements();
break;
default:
throw new BindingException("Unknown execution method for: " + this.command.getName());
}
if (result == null && this.method.getReturnType().isPrimitive() && !this.method.returnsVoid()) {
throw new BindingException("Mapper method '" + this.command.getName() + " attempted to return null from a method with a primitive return type (" + this.method.getReturnType() + ").");
} else {
return result;
}
}
这里,我们查询所有用户,执行executeForMany方法
// MapperMethod
private <E> Object executeForMany(SqlSession sqlSession, Object[] args) {
Object param = this.method.convertArgsToSqlCommandParam(args);
List result;
if (this.method.hasRowBounds()) {
RowBounds rowBounds = this.method.extractRowBounds(args);
result = sqlSession.selectList(this.command.getName(), param, rowBounds);
} else {
result = sqlSession.selectList(this.command.getName(), param);
}
if (!this.method.getReturnType().isAssignableFrom(result.getClass())) {
return this.method.getReturnType().isArray() ? this.convertToArray(result) : this.convertToDeclaredCollection(sqlSession.getConfiguration(), result);
} else {
return result;
}
}
调用默认实现DefaultSqlSession的selectList方法
// DefaultSqlSession
public <E> List<E> selectList(String statement, Object parameter) {
return this.selectList(statement, parameter, RowBounds.DEFAULT);
}
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
List var5;
try {
MappedStatement ms = this.configuration.getMappedStatement(statement); // 根据statement ID从configuration配置中获取MappedStatement
// 执行器执行查询任务
var5 = this.executor.query(ms, this.wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
} catch (Exception var9) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + var9, var9);
} finally {
ErrorContext.instance().reset();
}
return var5;
}
// BaseExecutor
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
BoundSql boundSql = ms.getBoundSql(parameter); // 根据参数动态组装执行sql
CacheKey key = this.createCacheKey(ms, parameter, rowBounds, boundSql); // 为当前查询任务创建缓存key
return this.query(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
if (this.closed) {
throw new ExecutorException("Executor was closed.");
} else {
if (this.queryStack == 0 && ms.isFlushCacheRequired()) {
this.clearLocalCache();
}
List list;
try {
++this.queryStack;
list = resultHandler == null ? (List)this.localCache.getObject(key) : null;
if (list != null) {
this.handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
} else {
list = this.queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql); // 从数据库中查询
}
} finally {
--this.queryStack;
}
if (this.queryStack == 0) {
Iterator var8 = this.deferredLoads.iterator();
while(var8.hasNext()) {
BaseExecutor.DeferredLoad deferredLoad = (BaseExecutor.DeferredLoad)var8.next();
deferredLoad.load();
}
this.deferredLoads.clear();
if (this.configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
this.clearLocalCache();
}
}
return list;
}
}
// 数据库查询
private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
this.localCache.putObject(key, ExecutionPlaceholder.EXECUTION_PLACEHOLDER);
List list;
try {
list = this.doQuery(ms, parameter, rowBounds, resultHandler, boundSql); // 查询结果
} finally {
this.localCache.removeObject(key);
}
this.localCache.putObject(key, list); // 将结果放入缓存中
if (ms.getStatementType() == StatementType.CALLABLE) {
this.localOutputParameterCache.putObject(key, parameter);
}
return list;
}
调用SimpleExecutor的doQuery方法
// SimpleExecutor
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Statement stmt = null;
List var9;
try {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(this.wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
stmt = this.prepareStatement(handler, ms.getStatementLog()); // 准备语句
var9 = handler.query(stmt, resultHandler);
} finally {
this.closeStatement(stmt);
}
return var9;
}
准备语句
// SimpleExecutor
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Connection connection = this.getConnection(statementLog); // 获取一个数据库连接对象
Statement stmt = handler.prepare(connection, this.transaction.getTimeout()); // 使用StatementHandler从数据库连接对象中获取Statement对象
handler.parameterize(stmt); // 设置参数 将sql语句中的占位符替换为具体参数
return stmt;
}
调用PreparedStatementHandler最终执行sql语句
// PreparedStatementHandler
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
PreparedStatement ps = (PreparedStatement)statement;
ps.execute(); // 执行具体sql语句
return this.resultSetHandler.handleResultSets(ps); // 处理结果集
}
从上面可以看出Executor的执行过程
- 首先获取一个数据库连接对象
- 使用StatementHandler.prepare()方法从数据库连接对象中获取Statement对象
- 使用StatementHandler.parameterize()方法将sql中占位符替换为具体执行参数
- 最后调用StatementHandler. query()方法执行sql
处理结果集
// DefaultResultSetHandler
public List<Object> handleResultSets(Statement stmt) throws SQLException {
ErrorContext.instance().activity("handling results").object(this.mappedStatement.getId());
List<Object> multipleResults = new ArrayList();
int resultSetCount = 0;
ResultSetWrapper rsw = this.getFirstResultSet(stmt);
List<ResultMap> resultMaps = this.mappedStatement.getResultMaps();
int resultMapCount = resultMaps.size();
this.validateResultMapsCount(rsw, resultMapCount);
while(rsw != null && resultMapCount > resultSetCount) {
ResultMap resultMap = (ResultMap)resultMaps.get(resultSetCount);
this.handleResultSet(rsw, resultMap, multipleResults, (ResultMapping)null);
rsw = this.getNextResultSet(stmt);
this.cleanUpAfterHandlingResultSet();
++resultSetCount;
}
String[] resultSets = this.mappedStatement.getResultSets();
if (resultSets != null) {
while(rsw != null && resultSetCount < resultSets.length) {
ResultMapping parentMapping = (ResultMapping)this.nextResultMaps.get(resultSets[resultSetCount]);
if (parentMapping != null) {
String nestedResultMapId = parentMapping.getNestedResultMapId();
ResultMap resultMap = this.configuration.getResultMap(nestedResultMapId);
this.handleResultSet(rsw, resultMap, (List)null, parentMapping);
}
rsw = this.getNextResultSet(stmt);
this.cleanUpAfterHandlingResultSet();
++resultSetCount;
}
}
return this.collapseSingleResultList(multipleResults);
}
整个执行过程完成。
更新流程分析
下面再看看更新操作,以saveUser方法为例分析更新流程(最终调用的都是update方法)
@Test
public void testSaveUser() {
User user = new User();
user.setAge(20);
user.setBirthday(new Date());
user.setName("test_name_22");
user.setPassword("123456");
user.setSex(1);
user.setUserName("test_userName_22");
userMapper.saveUser(user);
}
执行insert、update、delete最后调用的都是下面update方法
// DefaultSqlSession
public int update(String statement, Object parameter) {
int var4;
try {
this.dirty = true;
MappedStatement ms = this.configuration.getMappedStatement(statement); // 获取对应的MappedStatement
var4 = this.executor.update(ms, this.wrapCollection(parameter)); // 执行更新操作(包括包装集合类型参数)
} catch (Exception var8) {
throw ExceptionFactory.wrapException("Error updating database. Cause: " + var8, var8);
} finally {
ErrorContext.instance().reset();
}
return var4;
}
// BaseExecutor
public int update(MappedStatement ms, Object parameter) throws SQLException {
ErrorContext.instance().resource(ms.getResource()).activity("executing an update").object(ms.getId());
if (this.closed) {
throw new ExecutorException("Executor was closed.");
} else {
this.clearLocalCache(); // 清除本地缓存
return this.doUpdate(ms, parameter); // 执行更新操作
}
}
// SimpleExecutor
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
Statement stmt = null;
int var6;
try {
Configuration configuration = ms.getConfiguration(); // 获取全局配置信息configuration
// 创建StatementHandler
StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, (ResultHandler)null, (BoundSql)null);
stmt = this.prepareStatement(handler, ms.getStatementLog()); // 准备Statement
var6 = handler.update(stmt); // 处理更新操作
} finally {
this.closeStatement(stmt);
}
return var6;
}
最终执行update语句
// PreparedStatementHandler
public int update(Statement statement) throws SQLException {
PreparedStatement ps = (PreparedStatement)statement;
ps.execute(); // 执行语句
int rows = ps.getUpdateCount(); // 获取更新行数
Object parameterObject = this.boundSql.getParameterObject();
KeyGenerator keyGenerator = this.mappedStatement.getKeyGenerator(); // KeyGenerator后置处理
keyGenerator.processAfter(this.executor, this.mappedStatement, ps, parameterObject);
return rows;
}
这里重点分析下使用selectKey标签的SelectKeyGenerator实现
// SelectKeyGenerator
public void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
if (!this.executeBefore) { // 如果不是前置处理
this.processGeneratedKeys(executor, ms, parameter); // 处理生成的key
}
}
private void processGeneratedKeys(Executor executor, MappedStatement ms, Object parameter) {
try {
if (parameter != null && this.keyStatement != null && this.keyStatement.getKeyProperties() != null) {
String[] keyProperties = this.keyStatement.getKeyProperties(); // 获取配置key的属性信息
Configuration configuration = ms.getConfiguration(); // 获取全局配置参数configuration参数
MetaObject metaParam = configuration.newMetaObject(parameter);
if (keyProperties != null) {
Executor keyExecutor = configuration.newExecutor(executor.getTransaction(), ExecutorType.SIMPLE); // 创建执行器
List<Object> values = keyExecutor.query(this.keyStatement, parameter, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER); // 执行查询操作
if (values.size() == 0) { // 返回结果校验
throw new ExecutorException("SelectKey returned no data.");
}
if (values.size() > 1) {
throw new ExecutorException("SelectKey returned more than one value.");
}
MetaObject metaResult = configuration.newMetaObject(values.get(0));
if (keyProperties.length == 1) { // 只有一个参数属性
if (metaResult.hasGetter(keyProperties[0])) {
this.setValue(metaParam, keyProperties[0], metaResult.getValue(keyProperties[0]));
} else {
this.setValue(metaParam, keyProperties[0], values.get(0));
}
} else {
this.handleMultipleProperties(keyProperties, metaParam, metaResult); // 多个参数属性
}
}
}
} catch (ExecutorException var10) {
throw var10;
} catch (Exception var11) {
throw new ExecutorException("Error selecting key or setting result to parameter object. Cause: " + var11, var11);
}
}
private void handleMultipleProperties(String[] keyProperties, MetaObject metaParam, MetaObject metaResult) {
String[] keyColumns = this.keyStatement.getKeyColumns();
if (keyColumns != null && keyColumns.length != 0) {
if (keyColumns.length != keyProperties.length) {
throw new ExecutorException("If SelectKey has key columns, the number must match the number of key properties.");
}
for(int i = 0; i < keyProperties.length; ++i) {
this.setValue(metaParam, keyProperties[i], metaResult.getValue(keyColumns[i])); // 如果没有指定列表 则直接使用属性名称赋值
}
} else {
String[] var5 = keyProperties;
int var6 = keyProperties.length;
for(int var7 = 0; var7 < var6; ++var7) {
String keyProperty = var5[var7];
this.setValue(metaParam, keyProperty, metaResult.getValue(keyProperty)); // 使用列名赋值
}
}
}
根据方法返回值类型将影响行数转换为指定类型
// MapperMethod
private Object rowCountResult(int rowCount) {
Object result;
if (this.method.returnsVoid()) {
result = null;
} else if (!Integer.class.equals(this.method.getReturnType()) && !Integer.TYPE.equals(this.method.getReturnType())) {
if (!Long.class.equals(this.method.getReturnType()) && !Long.TYPE.equals(this.method.getReturnType())) {
if (!Boolean.class.equals(this.method.getReturnType()) && !Boolean.TYPE.equals(this.method.getReturnType())) {
throw new BindingException("Mapper method '" + this.command.getName() + "' has an unsupported return type: " + this.method.getReturnType());
}
result = rowCount > 0;
} else {
result = (long)rowCount;
}
} else {
result = rowCount;
}
return result;
}
更新操作流程分析完成。
参考资料
https://blog.csdn.net/ashan_li/article/details/50378393
https://blog.csdn.net/luanlouis/article/details/40422941
https://blog.csdn.net/heroqiang/article/details/79121516
https://www.cnblogs.com/jeffen/p/6277696.html?utm_source=itdadao&utm_medium=referral
http://www.ccblog.cn/88.htm