1、MyBatis逆向工程(Generator)
MyBatis Generator,简称MBG,是一个专门为MyBatis框架使用者定制的代码生成器,可以快速的根据表生成对应的映射文件,接口,以及bean类。支持基本的增删改查,以及QBC风格的条件查询。但是表连接,存储过程等这些复杂sql的定义需要我们手工编写
1、官方文档地址
2、官方工程地址
https://github.com/mybatis/generator
3、整合项目
1、下载包
https://github.com/mybatis/generator/releases
2、导入进项目
3、创建配置文件mbg.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<context id="DB2Tables" targetRuntime="MyBatis3">
<!-- 注释构建 -->
<commentGenerator>
<!-- 去掉所有的注释 -->
<property name="suppressAllComments" value="true"/>
<property name="suppressDate" value="true"/>
</commentGenerator>
<!--连接指定目标数据库-->
<jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/learn"
userId="root"
password="qwerasdf123">
<!-- MySQL 不支持 schema 或者 catalog 所以需要添加这个,官方文档有 -->
<property name="nullCatalogMeansCurrent" value="true"/>
</jdbcConnection>
<!--java类型解析器用默认-->
<javaTypeResolver >
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<!--生成bean路径和工程配置-->
<javaModelGenerator targetPackage="com.daijunyi.model" targetProject="./src">
<property name="enableSubPackages" value="true" />
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!--映射文件配置-->
<sqlMapGenerator targetPackage="com.daijunyi.mapper" targetProject="./src">
<property name="enableSubPackages" value="true" />
</sqlMapGenerator>
<!--mapper接口文件-->
<javaClientGenerator type="XMLMAPPER" targetPackage="com.daijunyi.mapper" targetProject="./src">
<property name="enableSubPackages" value="true" />
</javaClientGenerator>
<!--指定生成哪些表 domainObjectName:java类名 tableName:数据库表名-->
<table tableName="%"></table>
</context>
</generatorConfiguration>
4、创建代码生成各个文件
直接测试运行,就可以生成对应的表
@Test public void BGMTest() throws Exception{ List<String> warnings = new ArrayList<String>(); File configFile = new File("mbg.xml"); ConfigurationParser cp = new ConfigurationParser(warnings); Configuration config = cp.parseConfiguration(configFile); DefaultShellCallback callback = new DefaultShellCallback(true); MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings); myBatisGenerator.generate(null); }
5、运行完成之后就生成了对应的列
6、写测试代码
public SqlSessionFactory getSqlSessionFactory() { String resource = "mybatis.xml"; SqlSessionFactory sqlSessionFactory = null; try { InputStream inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { e.printStackTrace(); } return sqlSessionFactory; } @Test public void TestUser(){ SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(); SqlSession sqlSession = sqlSessionFactory.openSession(true); UserMapper mapper = sqlSession.getMapper(UserMapper.class); UserExample userExample = new UserExample(); UserExample.Criteria criteria = userExample.createCriteria(); criteria.andUserNameIn(Arrays.asList("红领巾")); List<User> users = mapper.selectByExample(userExample); System.out.println(users); }
2、MyBatis工作原理
1、架构图
2、SqlSessionFactory
1、获取SqlSessionFactory
String resource = "mybatis.xml"; SqlSessionFactory sqlSessionFactory = null; try { InputStream inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { e.printStackTrace(); } return sqlSessionFactory;
2、解析标签
private void parseConfiguration(XNode root) { try { // issue #117 read properties first propertiesElement(root.evalNode("properties")); Properties settings = settingsAsProperties(root.evalNode("settings")); loadCustomVfs(settings); loadCustomLogImpl(settings); typeAliasesElement(root.evalNode("typeAliases")); pluginElement(root.evalNode("plugins")); objectFactoryElement(root.evalNode("objectFactory")); objectWrapperFactoryElement(root.evalNode("objectWrapperFactory")); reflectorFactoryElement(root.evalNode("reflectorFactory")); settingsElement(settings); // read it after objectFactory and objectWrapperFactory issue #631 environmentsElement(root.evalNode("environments")); databaseIdProviderElement(root.evalNode("databaseIdProvider")); typeHandlerElement(root.evalNode("typeHandlers")); mapperElement(root.evalNode("mappers")); } catch (Exception e) { throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e); } }
一个MappedStatement代表一个增删改查的片段
- Configuration保存了所有的信息,包括sql信息等等
- 每一个Mapper接口文件对应一个MapperProxyFactory类
最终帮我们创建一个DefaultSqlSessionFactory
public SqlSessionFactory build(Configuration config) { return new DefaultSqlSessionFactory(config); }
3、时序图
3、SqlSession
1、创建SqlSession
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) { Transaction tx = null; try { final Environment environment = configuration.getEnvironment(); final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment); tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit); final Executor executor = configuration.newExecutor(tx, execType); return new DefaultSqlSession(configuration, executor, autoCommit); } catch (Exception e) { closeTransaction(tx); // may have fetched a connection so lets call close() throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e); } finally { ErrorContext.instance().reset(); } }
2、创建Executor
public Executor newExecutor(Transaction transaction, ExecutorType executorType) { executorType = executorType == null ? defaultExecutorType : executorType; executorType = executorType == null ? ExecutorType.SIMPLE : executorType; Executor 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 (cacheEnabled) { executor = new CachingExecutor(executor); } executor = (Executor) interceptorChain.pluginAll(executor); return executor; }
CachingExecutor(二级缓存)
interceptorChain.pluginAll(Executor)
再把executor传递给新创建DefaultSqlSession然后返回
new DefaultSqlSession(configuration, executor, autoCommit);
4、时序图
4、SqlSession.GetMapper
从Configuration中的MapperRegistry方法来创建
@SuppressWarnings("unchecked") public <T> T getMapper(Class<T> type, SqlSession sqlSession) { final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type); if (mapperProxyFactory == null) { throw new BindingException("Type " + type + " is not known to the MapperRegistry."); } try { return mapperProxyFactory.newInstance(sqlSession); } catch (Exception e) { throw new BindingException("Error getting mapper instance. Cause: " + e, e); } }
mapperProxyFactory.newInstance(sqlSeesion)
- 其实就是通过Proxy动态代理生成MapperProxy代理对象,
```java
@SuppressWarnings(“unchecked”)
protected T newInstance(MapperProxy
mapperProxy) { return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy); }
public T newInstance(SqlSession sqlSession) { final MapperProxy
mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache); return newInstance(mapperProxy); } <a name="owdNZ"></a> ### 1、时序图  <a name="nOK9k"></a> ## 5、执行具体接口获取结果 <a name="P3uGN"></a> ### 1、直接进入MapperProxy代理对象中调用 ```java @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { if (Object.class.equals(method.getDeclaringClass())) { return method.invoke(this, args); } else { return cachedInvoker(method).invoke(proxy, method, args, sqlSession); } } catch (Throwable t) { throw ExceptionUtil.unwrapThrowable(t); } }
- 其实就是通过Proxy动态代理生成MapperProxy代理对象,
```java
@SuppressWarnings(“unchecked”)
protected T newInstance(MapperProxy
判断如果是object类的方法就直接放行
Object.class.equals(method.getDeclaringClass())
2、Execute
public Object execute(SqlSession sqlSession, Object[] args) { Object result; switch (command.getType()) { case INSERT: { Object param = method.convertArgsToSqlCommandParam(args); result = rowCountResult(sqlSession.insert(command.getName(), param)); break; } case UPDATE: { Object param = method.convertArgsToSqlCommandParam(args); result = rowCountResult(sqlSession.update(command.getName(), param)); break; } case DELETE: { Object param = method.convertArgsToSqlCommandParam(args); result = rowCountResult(sqlSession.delete(command.getName(), param)); break; } case SELECT: if (method.returnsVoid() && method.hasResultHandler()) { executeWithResultHandler(sqlSession, args); result = null; } else if (method.returnsMany()) { result = executeForMany(sqlSession, args); } else if (method.returnsMap()) { result = executeForMap(sqlSession, args); } else if (method.returnsCursor()) { result = executeForCursor(sqlSession, args); } else { Object param = method.convertArgsToSqlCommandParam(args); result = sqlSession.selectOne(command.getName(), param); if (method.returnsOptional() && (result == null || !method.getReturnType().equals(result.getClass()))) { result = Optional.ofNullable(result); } } break; case FLUSH: result = sqlSession.flushStatements(); break; default: throw new BindingException("Unknown execution method for: " + command.getName()); } if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) { throw new BindingException("Mapper method '" + command.getName() + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ")."); } return result; }
加入我们现在查询单个对象返回的
- 调用result = sqlSession.selectOne(command.getName(), param);
最终调用DefaultSqlSession中的selectList
private <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) { try { MappedStatement ms = configuration.getMappedStatement(statement); return executor.query(ms, wrapCollection(parameter), rowBounds, handler); } catch (Exception e) { throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e); } finally { ErrorContext.instance().reset(); } }
executor调用query
- 获取到BoundSql是具体的sql信息
- 创建出缓存key的值特别复杂如下
- 374417829:4136890107:com.daijunyi.mapper.UserMapper.getUserList:0:2147483647:select * from
user
:development@Override public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException { BoundSql boundSql = ms.getBoundSql(parameterObject); CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql); return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); }
- 374417829:4136890107:com.daijunyi.mapper.UserMapper.getUserList:0:2147483647:select * from
BoundSql ```java public class BoundSql {
private final String sql; private final List
parameterMappings; private final Object parameterObject; private final Map additionalParameters; private final MetaObject metaParameters;
- 最终query调用查询
- 这里List<E> list = (List<E>) tcm.getObject(cache, key); 是调用二级缓存查询是否存在,如果存在就直接返回
- delegate就是我们全局配置的另外一个SimpleExecutor
```java
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
throws SQLException {
Cache cache = ms.getCache();
if (cache != null) {
flushCacheIfRequired(ms);
if (ms.isUseCache() && resultHandler == null) {
ensureNoOutParams(ms, boundSql);
@SuppressWarnings("unchecked")
List<E> list = (List<E>) tcm.getObject(cache, key);
if (list == null) {
list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
tcm.putObject(cache, key, list); // issue #578 and #116
}
return list;
}
}
return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
SimpleExecutor.query
- list = resultHandler == null ? (List
) localCache.getObject(key) : null; 查看本地缓存(一级缓存)是否存在 - 不存在就调用queryFromDatabase调用数据库
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 (closed) { throw new ExecutorException("Executor was closed."); } if (queryStack == 0 && ms.isFlushCacheRequired()) { clearLocalCache(); } List<E> list; try { queryStack++; list = resultHandler == null ? (List<E>) localCache.getObject(key) : null; if (list != null) { handleLocallyCachedOutputParameters(ms, key, parameter, boundSql); } else { list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql); } } finally { queryStack--; } if (queryStack == 0) { for (DeferredLoad deferredLoad : deferredLoads) { deferredLoad.load(); } // issue #601 deferredLoads.clear(); if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) { // issue #482 clearLocalCache(); } } return list; }
- list = resultHandler == null ? (List
queryFromDatabase查询数据库
- ms 当前sql片段的详细信息包括接口文件 映射文件等信息
- parameter参数信息
- boundSql Sql语句信息
- rowBounds 逻辑分页的
private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { List<E> list; localCache.putObject(key, EXECUTION_PLACEHOLDER); try { list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql); } finally { localCache.removeObject(key); } localCache.putObject(key, list); if (ms.getStatementType() == StatementType.CALLABLE) { localOutputParameterCache.putObject(key, parameter); } return list; }
doQuery
- StatementHandler 可以用来创建Statement
@Override public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { Statement stmt = null; try { Configuration configuration = ms.getConfiguration(); StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql); stmt = prepareStatement(handler, ms.getStatementLog()); return handler.query(stmt, resultHandler); } finally { closeStatement(stmt); } }
- StatementHandler 可以用来创建Statement
configuration.newStatementHandler
- statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
- 拦截器进一步包装
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql); statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler); return statementHandler; }
- 拦截器进一步包装
- statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
ResultSetHandler和StatementHandler创建
- StatementHandler参数预编译
ResultSetHandler返回结果处理器
- 都通过了interceptorChain的包装 ```java public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler, ResultHandler resultHandler, BoundSql boundSql) { ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds); resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler); return resultSetHandler; }
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql); statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler); return statementHandler; } ```
3、流程图
6、总结:
(1)根据配置文件(全局,sql映射)初始化出Configuration对象
(2)创建一个DefaultSqlSession对象,他里面包含Configuration以及Executor(根据全局配置文件中的defaultExecutorType创建出对应的Executor)
(3)DefaultSqlSession.getMapper():拿到Mapper接口对应的MapperProxy动态代理对象
(4)MapperProxy里面有(DefaultSqlSession)
(5)执行增删改查方法:
- (1)调用DefaultSqlSession的增删改查(Executor)
- (2)创建一个Statement对象。(同时也会创建出ParameterHandler和ResultSetHandler)
- (3)调用StatementHandler预编译参数以及设置参数值;使用ParameterHandler给sql设置参数
- (4)调用StatementHandler的增删改查方法
- (5)ResultSetHandler封装结果
注意:
- 四大对象Executor、ParameterHandler、ResultSetHandler、StatementHandler都会有一个拦截器包装的过程
3、插件开发
1、简介
- MyBatis在四大对象的创建过程中,都会有插件进行介入。插件可以利用动态代理机制-层层的包装目标对象,而实现在目标对象执行目标方法之前进行拦截的效果
- MyBatis允许在已映射语句执行过程中的某一点进行拦截调用。
- 默认情况下,MyBatis允许使用插件来拦截的方法调用包括
package com.daijunyi.interceptor;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.plugin.*;
import java.sql.Statement;
import java.util.Properties;
@Intercepts(value = {@Signature(type = ResultSetHandler.class,method = "handleResultSets",args = {Statement.class})})
public class MyMybatisPlugin implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
System.out.println("MyMybatisPlugin...intercept");
Object proceed = invocation.proceed();
return proceed;
}
@Override
public Object plugin(Object target) {
System.out.println("包装对象对:"+target.getClass().getName());
Object wrap = Plugin.wrap(target, this);
System.out.println("包装对象后:"+wrap.getClass().getName());
return wrap;
}
@Override
public void setProperties(Properties properties) {
System.out.println("MyMybatisPlugin:"+properties.toString());
}
}
<plugins>
<plugin interceptor="com.daijunyi.interceptor.MyMybatisPlugin">
<property name="tx" value="11"/>
</plugin>
</plugins>
运行结果:
[DEBUG][2021-08-12 22:07:12 771][org.apache.ibatis.io.ResolverUtil]-[Checking to see if class com.daijunyi.interceptor.MyMybatisPlugin matches criteria [is assignable to Object]]
[DEBUG][2021-08-12 22:07:12 771][org.apache.ibatis.io.ResolverUtil]-[Checking to see if class com.daijunyi.mapper.UserMapper matches criteria [is assignable to Object]]
[DEBUG][2021-08-12 22:07:12 772][org.apache.ibatis.io.ResolverUtil]-[Checking to see if class com.daijunyi.model.User matches criteria [is assignable to Object]]
[DEBUG][2021-08-12 22:07:12 772][org.apache.ibatis.io.ResolverUtil]-[Checking to see if class com.daijunyi.test.BGMTest matches criteria [is assignable to Object]]
MyMybatisPlugin:{tx=11}
[DEBUG][2021-08-12 22:07:12 802][org.apache.ibatis.datasource.pooled.PooledDataSource]-[PooledDataSource forcefully closed/removed all connections.]
[DEBUG][2021-08-12 22:07:12 802][org.apache.ibatis.datasource.pooled.PooledDataSource]-[PooledDataSource forcefully closed/removed all connections.]
[DEBUG][2021-08-12 22:07:12 802][org.apache.ibatis.datasource.pooled.PooledDataSource]-[PooledDataSource forcefully closed/removed all connections.]
[DEBUG][2021-08-12 22:07:12 803][org.apache.ibatis.datasource.pooled.PooledDataSource]-[PooledDataSource forcefully closed/removed all connections.]
[DEBUG][2021-08-12 22:07:13 233][org.apache.ibatis.datasource.pooled.PooledDataSource]-[Created connection 1927963027.]
[DEBUG][2021-08-12 22:07:13 236][org.apache.ibatis.datasource.pooled.PooledDataSource]-[Returned connection 1927963027 to pool.]
包装对象对:org.apache.ibatis.executor.CachingExecutor
包装对象后:org.apache.ibatis.executor.CachingExecutor
包装对象对:org.apache.ibatis.scripting.defaults.DefaultParameterHandler
包装对象后:org.apache.ibatis.scripting.defaults.DefaultParameterHandler
包装对象对:org.apache.ibatis.executor.resultset.DefaultResultSetHandler
包装对象后:com.sun.proxy.$Proxy10
包装对象对:org.apache.ibatis.executor.statement.RoutingStatementHandler
包装对象后:org.apache.ibatis.executor.statement.RoutingStatementHandler
[DEBUG][2021-08-12 22:10:03 820][org.apache.ibatis.transaction.jdbc.JdbcTransaction]-[Opening JDBC Connection]
[DEBUG][2021-08-12 22:10:03 823][org.apache.ibatis.datasource.pooled.PooledDataSource]-[Checked out connection 1927963027 from pool.]
[DEBUG][2021-08-12 22:10:07 233][com.daijunyi.mapper.UserMapper.getUserList]-[==> Preparing: select * from `user`]
[DEBUG][2021-08-12 22:10:08 002][com.daijunyi.mapper.UserMapper.getUserList]-[==> Parameters: ]
MyMybatisPlugin...intercept
[DEBUG][2021-08-12 22:11:19 949][com.daijunyi.mapper.UserMapper.getUserList]-[<== Total: 15]
[User{userId=2, userName='红领巾', uStatus=2}, User{userId=111, userName='白毛女', uStatus=2}, User{userId=112, userName='红领巾3', uStatus=2}, User{userId=113, userName='红领巾3', uStatus=2}, User{userId=114, userName='红领巾3', uStatus=2}, User{userId=115, userName='红领巾3', uStatus=2}, User{userId=116, userName='红领巾3', uStatus=2}, User{userId=117, userName='111', uStatus=1}, User{userId=118, userName='红林俊杰', uStatus=2}, User{userId=119, userName='11111', uStatus=1}, User{userId=120, userName='红林俊杰11', uStatus=2}, User{userId=121, userName='11111', uStatus=1}, User{userId=122, userName='红林俊杰11', uStatus=2}, User{userId=123, userName='11111', uStatus=1}, User{userId=124, userName='红林俊杰11', uStatus=2}]
Disconnected from the target VM, address: '127.0.0.1:49288', transport: 'socket'
Process finished with exit code 0
3、比如我们修改一个查询语句拦截参考
- parameterHandler.mappedStatement是拿出了PreparedStatementHandler中的parameterHandler(DefaultParameterHandler)对象中的mappedStatement
SystemMetaObject就是个反射工具
@Intercepts(@Signature(type = StatementHandler.class, method = "parameterize", args = {Statement.class})) public class MyStatementHandlerPlugin implements Interceptor { @Override public Object intercept(Invocation invocation) throws Throwable { Object target = invocation.getTarget(); MetaObject metaObject = SystemMetaObject.forObject(target); Object obj = metaObject.getValue("parameterHandler.mappedStatement"); if (obj instanceof MappedStatement){ MappedStatement mappedStatement = (MappedStatement) obj; String id = mappedStatement.getId(); if (id !=null && "com.daijunyi.mapper.UserMapper.getUserList".equals(id)){ Object value = metaObject.getValue("parameterHandler.parameterObject"); if (value != null && value instanceof Integer){ metaObject.setValue("parameterHandler.parameterObject",124); } } } Object proceed = invocation.proceed(); return proceed; } @Override public Object plugin(Object target) { Object wrap = Plugin.wrap(target, this); return wrap; } @Override public void setProperties(Properties properties) { } }
4、批量操作
1、开启一个批处理sqlSession
sqlSessionFactory.openSession(ExecutorType.BATCH);
public SqlSessionFactory getSqlSessionFactory() { String resource = "mybatis.xml"; SqlSessionFactory sqlSessionFactory = null; try { InputStream inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { e.printStackTrace(); } return sqlSessionFactory; } @Test public void addUser(){ SqlSession sqlSession = null; long beforeTime = 0; try { SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(); sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH); UserMapper mapper = sqlSession.getMapper(UserMapper.class); Random random = new Random(); beforeTime = System.currentTimeMillis(); for (int i=0;i<10000;i++){ int t = mapper.addUser(new User(UUID.randomUUID().toString().substring(0, 10), random.nextInt(2))); } sqlSession.commit(); } catch (Exception e) { e.printStackTrace(); } finally { if (sqlSession != null){ sqlSession.close(); } } long time = System.currentTimeMillis() - beforeTime; System.out.println(time); }
2、SpringMVC中配置批处理
在Spring的配置文件 applicationContext.xml文件中
<!--整合mybatis spring 管理所有组件 1、使用 --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <!--指定配置文件--> <property name="configLocation" value="classpath:mybatis-config.xml"/> <!--指定映射文件--> <property name="mapperLocations" value="classpath:mapper/*.xml"/> </bean> <!--配置批处理sqlSession--> <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate"> <constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"/> <constructor-arg name="executorType" value="BATCH"/> </bean>
5、存储过程
6、自定义类型处理器
1、默认枚举处理器
EnumOrdinalTypeHandler:处理是把枚举类型转换为index的处理器ordinal()方法
- EnumTypeHandler:处理是把枚举转换为枚举名称的处理name()方法
(1)创建枚举类
public enum UStatus {
Live,Die
}
(2)修改User
package com.daijunyi.model;
public class User {
private Integer userId;
private String userName;
private UStatus uStatus;
public User() {
}
public User(String userName, UStatus uStatus) {
this.userName = userName;
this.uStatus = uStatus;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName == null ? null : userName.trim();
}
public UStatus getuStatus() {
return uStatus;
}
public void setuStatus(UStatus uStatus) {
this.uStatus = uStatus;
}
@Override
public String toString() {
return "User{" +
"userId=" + userId +
", userName='" + userName + '\'' +
", uStatus=" + uStatus +
'}';
}
}
(3)数据库类型
(4)配置MyBatis类型处理器
- 指定java类型
- 指定jdbc类型INTEGER 是在(java.sql.JDBCType)中查看
<typeHandlers> <typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler" javaType="com.daijunyi.model.UStatus" jdbcType="INTEGER"/> </typeHandlers>
2、自定义处理器类型
假如我们的枚举类型如下
我们想把0 1 10存进数据库
而返回给前端的时候是msg 活着 死了 未知这样 就需要我们自定义类型了 ```java package com.daijunyi.model;
public enum UStatus { Live(0,”活着”),Die(1,”死了”),UnKnow(10,”未知”);
private String msg;
private Integer code;
UStatus(Integer code,String msg) {
this.msg = msg;
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public static UStatus getUStatusByCode(Integer code){
switch (code){
case 0:
return UStatus.Live;
case 1:
return UStatus.Die;
default:
return UStatus.UnKnow;
}
}
}
- 自定义类型处理器
```java
package com.daijunyi.typehandler;
import com.daijunyi.model.UStatus;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandler;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class UStatueTypeHandler implements TypeHandler<UStatus> {
//保存到数据库的时候调用的方法
@Override
public void setParameter(PreparedStatement ps, int i, UStatus parameter, JdbcType jdbcType) throws SQLException {
ps.setInt(i,parameter.getCode());
}
//查询
@Override
public UStatus getResult(ResultSet rs, String columnName) throws SQLException {
int code = rs.getInt(columnName);
UStatus uStatusByCode = UStatus.getUStatusByCode(code);
return uStatusByCode;
}
//根据列查询
@Override
public UStatus getResult(ResultSet rs, int columnIndex) throws SQLException {
int code = rs.getInt(columnIndex);
UStatus uStatusByCode = UStatus.getUStatusByCode(code);
return uStatusByCode;
}
//调用存储过程封装结果
@Override
public UStatus getResult(CallableStatement cs, int columnIndex) throws SQLException {
int code = cs.getInt(columnIndex);
UStatus uStatusByCode = UStatus.getUStatusByCode(code);
return uStatusByCode;
}
}
配置类型处理器
<typeHandlers> <typeHandler handler="com.daijunyi.typehandler.UStatueTypeHandler" javaType="com.daijunyi.model.UStatus" jdbcType="INTEGER"/> </typeHandlers>
存储进数据库的数据