├── .gitignore ├── README.md ├── _config.yml ├── doc ├── executor.jpg ├── mybatis ambiguous问题分析.md ├── mybatis collection集合嵌套查询树形节点.md ├── mybatis plugin原理分析.md ├── mybatis-Executor原理分析.md ├── mybatis在spring中注入接口原理分析上篇.md ├── mybatis在spring中注入接口原理分析下篇.md ├── mybatis缓存原理分析.md └── mybatis缓存架构示意图.png ├── mybatis-base ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── github │ │ └── base │ │ ├── bean │ │ ├── MyPage.java │ │ ├── Order.java │ │ ├── Role.java │ │ ├── SEX.java │ │ ├── Student.java │ │ └── User.java │ │ ├── mapper │ │ ├── OrderMapper.java │ │ ├── RoleMapper.java │ │ ├── StudentMapper.java │ │ └── UserMapper.java │ │ ├── resulthandler │ │ └── UserResultHandler.java │ │ ├── typeHandler │ │ └── MySexTypeHandler.java │ │ └── util │ │ ├── JSONUtil.java │ │ ├── PrintUtil.java │ │ ├── ReflectUtil.java │ │ ├── SqlHelper.java │ │ └── TimeUtils.java │ └── resources │ ├── dbConfig.properties │ ├── logback.xml │ ├── mapper │ ├── RoleMapper.xml │ └── UserMapper.xml │ └── sql │ ├── run.sql │ └── student.sql ├── mybatis-core ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── github │ │ └── core │ │ ├── builder │ │ ├── CacheBuilder.java │ │ ├── MyBatisCoreBuilder.java │ │ └── SqlPrintBuilder.java │ │ ├── cache │ │ └── MyCache.java │ │ ├── plugin │ │ ├── PagePlugin.java │ │ └── PerformanceInterceptor.java │ │ └── util │ │ └── MyBatisConfigHelper.java │ └── resources │ └── mybatis-config.xml ├── mybatis-generator ├── README.md ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── github │ │ └── generator │ │ ├── GeneratorPostgresTest.java │ │ ├── GeneratorTest.java │ │ └── MyCommentGenerator.java │ └── resources │ ├── example.xml │ ├── generatorConfig.xml │ ├── generatorConfigByMaven.xml │ └── generatorPostgresConfig.xml ├── mybatis-mapper ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── github │ │ └── mapper │ │ ├── mapper │ │ ├── CommonMapper.java │ │ ├── InsertLogIdMapper.java │ │ └── UserLoginMapper.java │ │ ├── model │ │ └── UserLogin.java │ │ ├── plugin │ │ └── PerformanceInterceptor.java │ │ ├── test │ │ └── CommonMapperTest.java │ │ └── util │ │ └── CommonMapperHelper.java │ └── resources │ ├── dbConfig.properties │ ├── generatorConfigByMaven.xml │ └── mybatis-config.xml ├── mybatis-order ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── github │ │ └── order │ │ ├── OrderByTest.java │ │ └── util │ │ └── OrderConfigHelper.java │ └── resources │ └── order-config.xml ├── mybatis-page ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── github │ │ └── page │ │ ├── PageInterceptorTest.java │ │ ├── plugin │ │ └── PerformanceInterceptor.java │ │ └── util │ │ └── PageConfigHelper.java │ └── resources │ └── page-config.xml ├── mybatis-plugin ├── README.md ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── github │ │ │ └── plugin │ │ │ ├── PluginUtils.java │ │ │ ├── id │ │ │ ├── AutoIncrementKeyPlugin.java │ │ │ ├── IDGen.java │ │ │ ├── PropertyColumnPair.java │ │ │ └── package-info.java │ │ │ ├── monitor │ │ │ ├── DefaultMonitor.java │ │ │ ├── Monitor.java │ │ │ └── MonitorInterceptor.java │ │ │ └── rw │ │ │ ├── DataSourceSwitchFactoryBean.java │ │ │ ├── DataSourceSwitchInterceptor.java │ │ │ ├── plan1 │ │ │ ├── DataSource.java │ │ │ ├── DynamicDataSource.java │ │ │ ├── DynamicDataSourceAspect.java │ │ │ ├── DynamicDataSourceGlobal.java │ │ │ └── DynamicDataSourceHolder.java │ │ │ ├── plan2 │ │ │ ├── AbstractDynamicDataSourceProxy.java │ │ │ ├── ConnectionProxy.java │ │ │ ├── DynamicPlugin.java │ │ │ └── DynamicRoutingDataSourceProxy.java │ │ │ └── plan3 │ │ │ ├── DynamicDataSource.java │ │ │ ├── DynamicDataSourceGlobal.java │ │ │ ├── DynamicDataSourceHolder.java │ │ │ ├── DynamicDataSourceTransactionManager.java │ │ │ └── DynamicPlugin.java │ └── resources │ │ └── plugin │ │ └── rw │ │ ├── plan1 │ │ └── rw2.xml │ │ └── rwDbConfig.properties │ └── test │ ├── java │ └── com │ │ └── github │ │ └── plugin │ │ ├── id │ │ ├── AtomicLongIDGen.java │ │ ├── AutoIncrementKeyPluginTest.java │ │ └── MyBatisConfigHelper.java │ │ └── monitor │ │ ├── MonitorConfigHelper.java │ │ └── MonitorInterceptorTest.java │ └── resources │ ├── mybatis-config │ ├── idConfig.xml │ ├── monitorConfig.xml │ └── rwConfig.xml │ └── rw │ └── spring.xml ├── mybatis-spring ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── github │ │ └── spring │ │ ├── common │ │ └── CommonMapper.java │ │ ├── mapper │ │ └── UserLoginMapper.java │ │ ├── model │ │ └── UserLogin.java │ │ ├── plugin │ │ └── PerformanceInterceptor.java │ │ ├── service │ │ ├── RoleService.java │ │ ├── UserLoginService.java │ │ └── UserService.java │ │ └── web │ │ ├── UserController.java │ │ └── UserLoginController.java │ ├── resources │ ├── mybatis-config.xml │ ├── spring-mvc.xml │ └── spring.xml │ └── webapp │ ├── WEB-INF │ ├── views │ │ ├── user.jsp │ │ └── userLogin.jsp │ └── web.xml │ └── index.jsp └── pom.xml /.gitignore: -------------------------------------------------------------------------------- 1 | test-output/ 2 | tmp 3 | temp 4 | *.log 5 | 6 | 7 | ### Java template 8 | *.class 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.ear 17 | 18 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 19 | hs_err_pid* 20 | 21 | 22 | 23 | 24 | ### JetBrains template 25 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio 26 | 27 | *.iml 28 | 29 | ## Directory-based project format: 30 | .idea/ 31 | # if you remove the above rule, at least ignore the following: 32 | 33 | # User-specific stuff: 34 | # .idea/workspace.xml 35 | # .idea/tasks.xml 36 | # .idea/dictionaries 37 | 38 | # Sensitive or high-churn files: 39 | # .idea/dataSources.ids 40 | # .idea/dataSources.xml 41 | # .idea/sqlDataSources.xml 42 | # .idea/dynamic.xml 43 | # .idea/uiDesigner.xml 44 | 45 | # Gradle: 46 | # .idea/gradle.xml 47 | # .idea/libraries 48 | 49 | # Mongo Explorer plugin: 50 | # .idea/mongoSettings.xml 51 | 52 | ## File-based project format: 53 | *.ipr 54 | *.iws 55 | 56 | ## Plugin-specific files: 57 | 58 | # IntelliJ 59 | /out/ 60 | 61 | # mpeltonen/sbt-idea plugin 62 | .idea_modules/ 63 | 64 | # JIRA plugin 65 | atlassian-ide-plugin.xml 66 | 67 | # Crashlytics plugin (for Android Studio and IntelliJ) 68 | com_crashlytics_export_strings.xml 69 | crashlytics.properties 70 | crashlytics-build.properties 71 | 72 | 73 | 74 | ### Maven template 75 | target/ 76 | pom.xml.tag 77 | pom.xml.releaseBackup 78 | pom.xml.versionsBackup 79 | pom.xml.next 80 | release.properties 81 | dependency-reduced-pom.xml 82 | buildNumber.properties 83 | .mvn/timing.properties 84 | 85 | 86 | 87 | ### SVN template 88 | .svn/ 89 | 90 | 91 | 92 | ### Eclipse template 93 | *.pydevproject 94 | .metadata 95 | .gradle 96 | bin/ 97 | tmp/ 98 | *.tmp 99 | *.bak 100 | *.swp 101 | *~.nib 102 | local.properties 103 | .settings/ 104 | .loadpath 105 | 106 | # Eclipse Core 107 | .project 108 | 109 | # External tool builders 110 | .externalToolBuilders/ 111 | 112 | # Locally stored "Eclipse launch configurations" 113 | *.launch 114 | 115 | # CDT-specific 116 | .cproject 117 | 118 | # JDT-specific (Eclipse Java Development Tools) 119 | .classpath 120 | 121 | # Java annotation processor (APT) 122 | .factorypath 123 | 124 | # PDT-specific 125 | .buildpath 126 | 127 | # sbteclipse plugin 128 | .target 129 | 130 | # TeXlipse plugin 131 | .texlipse 132 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mybatis 2 | 这里面是对mybatis的功能、原理研究以及一些常用plugin的整理,欢迎补充! 3 | 4 | --- 5 | 6 | ## 作者介绍 7 | 源码地址:我的[Github地址](https://github.com/benjaminwhx) 8 | 作者:[吴海旭](http://benjaminwhx.com) 9 | 10 | 11 | --- 12 | 13 | ## 项目结构 14 | 15 | | 编号 | 描述 | 16 | |--------|--------| 17 | |mybatis-core |mybatis基础功能(cache、crud、关联查询等测试) | 18 | |mybatis-generator |mybatis generator测试 | 19 | |mybatis-mapper |mybatis通用mapper | 20 | |mybatis-order |mybatis排序插件 | 21 | |mybatis-page |mybatis分页插件 | 22 | |mybatis-plugin |项目中各种插件的使用 | 23 | |mybatis-spring |spring中mybatis的使用 | 24 | |doc |文档以及源码分析 | 25 | 26 | ## 文档地址 27 | 28 | 1、mybatis-page中文文档地址:[https://pagehelper.github.io/](https://pagehelper.github.io/) 29 | 2、mybatis-generator中文文档地址:[mybatis-generator](http://mbg.cndocs.tk/index.html) 30 | 3、mybatis相关工具地址:[http://www.mybatis.tk/](http://www.mybatis.tk/) 31 | 4、mybatis官方指南:[http://www.mybatis.org/mybatis-3/zh/index.html](http://www.mybatis.org/mybatis-3/zh/index.html) 32 | 5、mybatis-spring官方指南:[http://www.mybatis.org/spring/zh/index.html](http://www.mybatis.org/spring/zh/index.html) 33 | 34 | ## github地址 35 | 36 | 1、Mapper: [Mapper](https://github.com/abel533/Mapper) 37 | 2、PageHelper:[PageHelper](https://github.com/pagehelper/Mybatis-PageHelper) 38 | 39 | 中文注释:https://github.com/tuguangquan/mybatis 40 | 41 | mybatis设计模式:http://www.crazyant.net/2022.html 42 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /doc/executor.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benjaminwhx/p_mybatis/af9ae8bd2f02c056191793a9c1d87b66aee75675/doc/executor.jpg -------------------------------------------------------------------------------- /doc/mybatis ambiguous问题分析.md: -------------------------------------------------------------------------------- 1 | # mybatis ambiguous问题分析 2 | 3 | ## 1、问题描述 4 | ``` 5 | Caused by: java.lang.IllegalArgumentException: selectAccountById is ambiguous in Mapped Statements collection (try using the full name including the namespace, or rename one of the entries) 6 | ``` 7 | 这个问题其实不是mybatis的问题,字面意思就可以看出这个key模糊不清,没有指定namespace所导致的 8 | 9 | ## 2、问题起因以及解决方法 10 | 肯定是用户使用手动查询的时候没有指定namespace所导致的,应该是getSqlSession().selectList("com.xx.yy.findByIds")而不是etSqlSession().selectList("findByIds") 11 | 12 | ## 3、源码分析 13 | 在Configuration中有一个sql映射Map `mappedStatements`,它的类型是 `StrictMap`,这个map是mybatis自己定义的map,重写了put和get方法。下面是这两个方法的源码: 14 | 15 | ``` 16 | public V put(String key, V value) { 17 | if (containsKey(key)) { 18 | //如果已经存在此key了,直接报错 19 | throw new IllegalArgumentException(name + " already contains value for " + key); 20 | } 21 | if (key.contains(".")) { 22 | //如果有.符号,取得短名称,大致用意就是包名不同,类名相同,提供模糊查询的功能 23 | final String shortKey = getShortName(key); 24 | if (super.get(shortKey) == null) { 25 | //如果没有这个缩略,则放一个缩略 26 | super.put(shortKey, value); 27 | } else { 28 | //如果已经有此缩略,表示模糊,放一个Ambiguity型的 29 | super.put(shortKey, (V) new Ambiguity(shortKey)); 30 | } 31 | } 32 | //再放一个全名 33 | return super.put(key, value); 34 | //可以看到,如果有包名,会放2个key到这个map,一个缩略,一个全名 35 | } 36 | 37 | public V get(Object key) { 38 | V value = super.get(key); 39 | //如果找不到相应的key,直接报错 40 | if (value == null) { 41 | throw new IllegalArgumentException(name + " does not contain value for " + key); 42 | } 43 | //如果是模糊型的,也报错,提示用户 44 | if (value instanceof Ambiguity) { 45 | throw new IllegalArgumentException(((Ambiguity) value).getSubject() + " is ambiguous in " + name 46 | + " (try using the full name including the namespace, or rename one of the entries)"); 47 | } 48 | return value; 49 | } 50 | ``` 51 | 52 | 可以看到mybatis在初始化的时候,先把所有mapper文件的key(namespace+id)和对应的映射语句放到内存里,如果拿的时候根据namespace+id的规则来拿就不会有问题,但是如果只根据key来拿的话,就会让mybatis模糊,抛异常告诉用户。 53 | 54 | ## 4、结论 55 | 不同namespace可以指定相同id,手动查询的时候要使用namespace+id去查询。 -------------------------------------------------------------------------------- /doc/mybatis collection集合嵌套查询树形节点.md: -------------------------------------------------------------------------------- 1 | 传送门:[MyBatis collection 集合嵌套查询树形节点](https://mp.weixin.qq.com/s/fgjgP_f-CAf0ywc25VU0eA) -------------------------------------------------------------------------------- /doc/mybatis plugin原理分析.md: -------------------------------------------------------------------------------- 1 | ```java 2 | 3 | 4 | 5 | 6 | 7 | 8 | ``` 9 | 10 | 配置完成后,Configuration会进行解析,并加入配置的拦截器。 11 | ```java 12 | // 初始化拦截链 13 | protected final InterceptorChain interceptorChain = new InterceptorChain(); 14 | 15 | // 解析xml plugin节点 16 | private void pluginElement(XNode parent) throws Exception { 17 | if (parent != null) { 18 | for (XNode child : parent.getChildren()) { 19 | String interceptor = child.getStringAttribute("interceptor"); 20 | Properties properties = child.getChildrenAsProperties(); 21 | Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).newInstance(); 22 | interceptorInstance.setProperties(properties); 23 | configuration.addInterceptor(interceptorInstance); 24 | } 25 | } 26 | } 27 | 28 | // 把拦截器放入拦截链中 29 | public void addInterceptor(Interceptor interceptor) { 30 | interceptorChain.addInterceptor(interceptor); 31 | } 32 | ``` 33 | 34 | Configuration类中有几个方法通过 `interceptorChain.pluginAll()` 调用了自定义拦截器的plugin方法来生成代理对象,源码如下: 35 | 36 | ```java 37 | public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) { 38 | ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql); 39 | parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler); 40 | return parameterHandler; 41 | } 42 | 43 | public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler,ResultHandler resultHandler, BoundSql boundSql) { 44 | ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds); 45 | resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler); 46 | return resultSetHandler; 47 | } 48 | 49 | public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { 50 | StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql); 51 | statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler); 52 | return statementHandler; 53 | } 54 | 55 | public Executor newExecutor(Transaction transaction, ExecutorType executorType) { 56 | ... 57 | executor = (Executor) interceptorChain.pluginAll(executor); 58 | return executor; 59 | } 60 | ``` 61 | 62 | 我们再来看看拦截链的源码,实际上mybatis的四大对象StatementHandler、ParameterHandler、ResultHandler和Executor都调用了pluginAll方法,并且都会进入你配置的拦截器的plugin方法: 63 | 64 | ```java 65 | public class InterceptorChain { 66 | 67 | private final List interceptors = new ArrayList(); 68 | 69 | /** 70 | * 对配置的plugin调用plugin方法 71 | */ 72 | public Object pluginAll(Object target) { 73 | for (Interceptor interceptor : interceptors) { 74 | target = interceptor.plugin(target); 75 | } 76 | return target; 77 | } 78 | 79 | public void addInterceptor(Interceptor interceptor) { 80 | interceptors.add(interceptor); 81 | } 82 | 83 | public List getInterceptors() { 84 | return Collections.unmodifiableList(interceptors); 85 | } 86 | 87 | } 88 | ``` 89 | 90 | 我们自己定义的拦截器的plugin方法实际上调用了Plugin的wrap方法,我们看看wrap的源码: 91 | 92 | ```java 93 | public static Object wrap(Object target, Interceptor interceptor) { 94 | // 获取自定义拦截器中定义的@Intercepts中配置的类和方法的map 95 | Map, Set> signatureMap = getSignatureMap(interceptor); 96 | // mybatis四大对象访问的类型 97 | Class type = target.getClass(); 98 | // 签名map中是否包含这4大对象的接口 99 | Class[] interfaces = getAllInterfaces(type, signatureMap); 100 | if (interfaces.length > 0) { 101 | // 如果存在,返回target的动态代理类 102 | return Proxy.newProxyInstance( 103 | type.getClassLoader(), 104 | interfaces, 105 | new Plugin(target, interceptor, signatureMap)); 106 | } 107 | // 返回原对象 108 | return target; 109 | } 110 | ``` 111 | 112 | 如果plugin返回的是target的代理类,那么后面执行target的方法时,就会进入Plugin的invoke方法中(不懂的请去了解jdk动态代理的相关知识) 113 | 114 | ```java 115 | @Override 116 | public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 117 | try { 118 | // 获取自定义拦截器中指定的方法,只有这些方法才会进行拦截 119 | Set methods = signatureMap.get(method.getDeclaringClass()); 120 | if (methods != null && methods.contains(method)) { 121 | // 走入自定义拦截器的intercept方法 122 | return interceptor.intercept(new Invocation(target, method, args)); 123 | } 124 | return method.invoke(target, args); 125 | } catch (Exception e) { 126 | throw ExceptionUtil.unwrapThrowable(e); 127 | } 128 | } 129 | ``` 130 | 131 | 既然走到自定义拦截器的intercept方法了,那么我们可以自己定义一些操作来拦截sql的执行,比如实现分页、分库分表的功能。具体的可以看我代码里的例子。 -------------------------------------------------------------------------------- /doc/mybatis缓存架构示意图.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benjaminwhx/p_mybatis/af9ae8bd2f02c056191793a9c1d87b66aee75675/doc/mybatis缓存架构示意图.png -------------------------------------------------------------------------------- /mybatis-base/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | mybatis 5 | com.github 6 | 1.0-SNAPSHOT 7 | 8 | 4.0.0 9 | 10 | mybatis-base 11 | jar 12 | 13 | mybatis-base 14 | http://maven.apache.org 15 | 16 | 17 | 18 | org.mybatis 19 | mybatis 20 | 21 | 22 | mysql 23 | mysql-connector-java 24 | 25 | 26 | org.slf4j 27 | slf4j-api 28 | 29 | 30 | ch.qos.logback 31 | logback-classic 32 | 33 | 34 | org.logback-extensions 35 | logback-ext-spring 36 | 37 | 38 | com.alibaba 39 | fastjson 40 | 41 | 42 | commons-beanutils 43 | commons-beanutils 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /mybatis-base/src/main/java/com/github/base/bean/MyPage.java: -------------------------------------------------------------------------------- 1 | package com.github.base.bean; 2 | 3 | import java.util.HashMap; 4 | import java.util.List; 5 | import java.util.Map; 6 | 7 | /** 8 | * User: 吴海旭 9 | * Date: 2017-06-17 10 | * Time: 上午11:09 11 | */ 12 | public class MyPage { 13 | 14 | private int pageNo = 1; // 页码,默认第一页 15 | private int pageSize = 15; // 每页显示的记录数,默认15 16 | private int totalRecord; // 总记录数 17 | private int totalPage; // 总页数 18 | private List results; // 对应的当前记录页数 19 | private Map params = new HashMap<>(); // 其他的参数我们把它封装成一个map对象 20 | 21 | public int getPageNo() { 22 | return pageNo; 23 | } 24 | 25 | public void setPageNo(int pageNo) { 26 | this.pageNo = pageNo; 27 | } 28 | 29 | public int getPageSize() { 30 | return pageSize; 31 | } 32 | 33 | public void setPageSize(int pageSize) { 34 | this.pageSize = pageSize; 35 | } 36 | 37 | public int getTotalRecord() { 38 | return totalRecord; 39 | } 40 | 41 | public void setTotalRecord(int totalRecord) { 42 | this.totalRecord = totalRecord; 43 | //在设置总页数的时候计算出对应的总页数,在下面的三目运算中加法拥有更高的优先级,所以最后可以不加括号。 44 | int totalPage = totalRecord%pageSize==0 ? totalRecord/pageSize : totalRecord/pageSize + 1; 45 | this.setTotalPage(totalPage); 46 | } 47 | 48 | public int getTotalPage() { 49 | return totalPage; 50 | } 51 | 52 | public void setTotalPage(int totalPage) { 53 | this.totalPage = totalPage; 54 | } 55 | 56 | public List getResults() { 57 | return results; 58 | } 59 | 60 | public void setResults(List results) { 61 | this.results = results; 62 | } 63 | 64 | public Map getParams() { 65 | return params; 66 | } 67 | 68 | public void setParams(Map params) { 69 | this.params = params; 70 | } 71 | 72 | @Override 73 | public String toString() { 74 | StringBuilder builder = new StringBuilder(); 75 | builder.append("MyPage [pageNo=").append(pageNo).append(", pageSize=") 76 | .append(pageSize).append(", results=").append(results).append( 77 | ", totalPage=").append(totalPage).append( 78 | ", totalRecord=").append(totalRecord).append("]"); 79 | return builder.toString(); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /mybatis-base/src/main/java/com/github/base/bean/Order.java: -------------------------------------------------------------------------------- 1 | package com.github.base.bean; 2 | 3 | import org.apache.ibatis.type.Alias; 4 | 5 | import java.io.Serializable; 6 | 7 | /** 8 | * User: 吴海旭 9 | * Date: 2017-06-24 10 | * Time: 下午0:59 11 | */ 12 | @Alias("order") 13 | public class Order implements Serializable { 14 | private static final long serialVersionUID = 7799983304195819315L; 15 | private Long id; 16 | private String orderId; 17 | private String orderName; 18 | private User user; 19 | 20 | public Long getId() { 21 | return id; 22 | } 23 | 24 | public void setId(Long id) { 25 | this.id = id; 26 | } 27 | 28 | public String getOrderId() { 29 | return orderId; 30 | } 31 | 32 | public void setOrderId(String orderId) { 33 | this.orderId = orderId; 34 | } 35 | 36 | public String getOrderName() { 37 | return orderName; 38 | } 39 | 40 | public void setOrderName(String orderName) { 41 | this.orderName = orderName; 42 | } 43 | 44 | public User getUser() { 45 | return user; 46 | } 47 | 48 | public void setUser(User user) { 49 | this.user = user; 50 | } 51 | 52 | @Override 53 | public String toString() { 54 | return "Order{" + 55 | "id=" + id + 56 | ", orderId=" + orderId + 57 | ", orderName='" + orderName + '\'' + 58 | ", user=" + user + 59 | '}'; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /mybatis-base/src/main/java/com/github/base/bean/Role.java: -------------------------------------------------------------------------------- 1 | package com.github.base.bean; 2 | 3 | import org.apache.ibatis.type.Alias; 4 | 5 | import java.io.Serializable; 6 | 7 | /** 8 | * User: 吴海旭 9 | * Date: 2017-06-24 10 | * Time: 下午1:56 11 | */ 12 | @Alias("role") 13 | public class Role implements Serializable { 14 | private static final long serialVersionUID = 4214353179795248450L; 15 | private Long id; 16 | private String roleName; 17 | 18 | public Long getId() { 19 | return id; 20 | } 21 | 22 | public void setId(Long id) { 23 | this.id = id; 24 | } 25 | 26 | public String getRoleName() { 27 | return roleName; 28 | } 29 | 30 | public void setRoleName(String roleName) { 31 | this.roleName = roleName; 32 | } 33 | 34 | @Override 35 | public String toString() { 36 | return "Role{" + 37 | "id=" + id + 38 | ", roleName='" + roleName + '\'' + 39 | '}'; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /mybatis-base/src/main/java/com/github/base/bean/SEX.java: -------------------------------------------------------------------------------- 1 | package com.github.base.bean; 2 | 3 | import org.apache.ibatis.type.Alias; 4 | 5 | /** 6 | * User: 吴海旭 7 | * Date: 2017-06-13 8 | * Time: 下午6:38 9 | */ 10 | @Alias("sex") 11 | public enum SEX { 12 | 13 | MALE(1, "男"), 14 | FEMALE(2, "女"); 15 | 16 | private int code; 17 | private String des; 18 | 19 | SEX(int code, String des) { 20 | this.code = code; 21 | this.des = des; 22 | } 23 | 24 | public int getCode() { 25 | return code; 26 | } 27 | 28 | public String getDes() { 29 | return des; 30 | } 31 | 32 | public static SEX fromCode(int code) { 33 | for (SEX sex : SEX.values()) { 34 | if (sex.getCode() == code) { 35 | return sex; 36 | } 37 | } 38 | return null; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /mybatis-base/src/main/java/com/github/base/bean/Student.java: -------------------------------------------------------------------------------- 1 | package com.github.base.bean; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * User: 吴海旭 7 | * Date: 2017-06-28 8 | * Time: 下午6:11 9 | */ 10 | public class Student implements Serializable { 11 | private static final long serialVersionUID = 3246689245235341481L; 12 | private Long id; 13 | private String name; 14 | 15 | public String getName() { 16 | return name; 17 | } 18 | 19 | public void setName(String name) { 20 | this.name = name; 21 | } 22 | 23 | public Long getId() { 24 | return id; 25 | } 26 | 27 | public void setId(Long id) { 28 | this.id = id; 29 | } 30 | 31 | @Override 32 | public String toString() { 33 | return "Student{" + 34 | "id=" + id + 35 | ", name='" + name + '\'' + 36 | '}'; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /mybatis-base/src/main/java/com/github/base/bean/User.java: -------------------------------------------------------------------------------- 1 | package com.github.base.bean; 2 | 3 | import org.apache.ibatis.type.Alias; 4 | 5 | import java.io.Serializable; 6 | import java.util.List; 7 | 8 | /** 9 | * User: 吴海旭 10 | * Date: 2017-06-24 11 | * Time: 下午0:55 12 | */ 13 | @Alias("user") 14 | public class User implements Serializable { 15 | private static final long serialVersionUID = -6532514335200325000L; 16 | private Long id; 17 | private String userName; 18 | private SEX sex; 19 | private Long roleId; 20 | private List orderList; 21 | private Role role; 22 | 23 | public Long getId() { 24 | return id; 25 | } 26 | 27 | public void setId(Long id) { 28 | this.id = id; 29 | } 30 | 31 | public String getUserName() { 32 | return userName; 33 | } 34 | 35 | public void setUserName(String userName) { 36 | this.userName = userName; 37 | } 38 | 39 | public Long getRoleId() { 40 | return roleId; 41 | } 42 | 43 | public void setRoleId(Long roleId) { 44 | this.roleId = roleId; 45 | } 46 | 47 | public SEX getSex() { 48 | return sex; 49 | } 50 | 51 | public void setSex(SEX sex) { 52 | this.sex = sex; 53 | } 54 | 55 | public List getOrderList() { 56 | return orderList; 57 | } 58 | 59 | public void setOrderList(List orderList) { 60 | this.orderList = orderList; 61 | } 62 | 63 | public Role getRole() { 64 | return role; 65 | } 66 | 67 | public void setRole(Role role) { 68 | this.role = role; 69 | } 70 | 71 | @Override 72 | public String toString() { 73 | return "User{" + 74 | "id=" + id + 75 | ", userName='" + userName + '\'' + 76 | ", sex=" + sex + 77 | ", roleId=" + roleId + 78 | ", orderList=" + orderList + 79 | ", role=" + role + 80 | '}'; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /mybatis-base/src/main/java/com/github/base/mapper/OrderMapper.java: -------------------------------------------------------------------------------- 1 | package com.github.base.mapper; 2 | 3 | import com.github.base.bean.Order; 4 | import org.apache.ibatis.annotations.*; 5 | import org.apache.ibatis.jdbc.SQL; 6 | 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | /** 11 | * User: 吴海旭 12 | * Date: 2017-06-24 13 | * Time: 下午2:10 14 | */ 15 | public interface OrderMapper { 16 | 17 | @Results(id = "orderResult", value = { 18 | @Result(property = "orderId", column = "order_id"), 19 | @Result(property = "orderName", column = "order_name") 20 | }) 21 | @SelectProvider(type = selectSqlBuilder.class, method = "getOrdersByIds") 22 | List findOrderByIds(@Param("ids") List ids); 23 | 24 | class selectSqlBuilder { 25 | public String getOrdersByIds(Map parameters) { 26 | final List ids = (List) parameters.get("ids"); 27 | return new SQL(){{ 28 | SELECT("*"); 29 | FROM("cf_order"); 30 | if (ids != null && ids.size() > 0) { 31 | StringBuilder idIn = new StringBuilder(); 32 | for (String id : ids) { 33 | idIn.append(id).append(","); 34 | } 35 | String idStr = idIn.substring(0, idIn.length() - 1); 36 | WHERE("id in (" + idStr + ")"); 37 | } 38 | }}.toString(); 39 | } 40 | } 41 | 42 | @Results(id = "orderResult2", value = { 43 | @Result(property = "orderId", column = "order_id"), 44 | @Result(property = "orderName", column = "order_name"), 45 | // @Result(property = "user", column = "uid", 46 | // one = @One( 47 | // select = "com.jd.jr.bt.mybatis.mapper.xml.UserMapper.getUserByUserId", fetchType = FetchType.LAZY 48 | // )) 49 | }) 50 | @Select("select * from cf_order a where a.uid = #{uid}") 51 | List getOrdersByUid(@Param("uid") Long uid); 52 | } 53 | -------------------------------------------------------------------------------- /mybatis-base/src/main/java/com/github/base/mapper/RoleMapper.java: -------------------------------------------------------------------------------- 1 | package com.github.base.mapper; 2 | 3 | import com.github.base.bean.Role; 4 | import org.apache.ibatis.annotations.Param; 5 | 6 | /** 7 | * User: 吴海旭 8 | * Date: 2017-06-24 9 | * Time: 下午2:05 10 | */ 11 | public interface RoleMapper { 12 | 13 | Role findRoleById(@Param("id") Long id); 14 | } 15 | -------------------------------------------------------------------------------- /mybatis-base/src/main/java/com/github/base/mapper/StudentMapper.java: -------------------------------------------------------------------------------- 1 | package com.github.base.mapper; 2 | 3 | import com.github.base.bean.Student; 4 | import org.apache.ibatis.annotations.Delete; 5 | import org.apache.ibatis.annotations.Insert; 6 | import org.apache.ibatis.annotations.Select; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * User: 吴海旭 12 | * Date: 2017-06-28 13 | * Time: 下午6:12 14 | */ 15 | public interface StudentMapper { 16 | 17 | @Insert("insert into student(id, name) values(#{id}, #{name})") 18 | int insert(Student student); 19 | 20 | @Delete("delete from student") 21 | int deleteAll(); 22 | 23 | @Select("select * from student") 24 | List selectAll(); 25 | } 26 | -------------------------------------------------------------------------------- /mybatis-base/src/main/java/com/github/base/mapper/UserMapper.java: -------------------------------------------------------------------------------- 1 | package com.github.base.mapper; 2 | 3 | import com.github.base.bean.MyPage; 4 | import com.github.base.bean.User; 5 | import org.apache.ibatis.annotations.Flush; 6 | import org.apache.ibatis.annotations.Param; 7 | import org.apache.ibatis.session.ResultHandler; 8 | import org.apache.ibatis.session.RowBounds; 9 | 10 | import java.util.List; 11 | 12 | /** 13 | * User: 吴海旭 14 | * Date: 2017-06-24 15 | * Time: 下午1:01 16 | */ 17 | public interface UserMapper { 18 | 19 | /** 20 | * 插入 21 | * @param user 22 | * @return 23 | */ 24 | int insert(User user); 25 | 26 | /** 27 | * 批量插入 28 | * @param users 29 | * @return 30 | */ 31 | int insertBatch(List users); 32 | 33 | @Flush 34 | void flush(); 35 | 36 | /** 37 | * 更新 38 | * @param user 39 | * @return 40 | */ 41 | int update(User user); 42 | 43 | /** 44 | * 删除 45 | * @param id 46 | * @return 47 | */ 48 | int delete(Long id); 49 | 50 | /** 51 | * 通过id获取user 52 | * @param uid 53 | * @return 54 | */ 55 | User getUserByUserId(Long uid); 56 | 57 | void getUserByUserIdAndResultHandler(ResultHandler resultHandler); 58 | 59 | /** 60 | * 使用@Param来定义参数名获取user 61 | * @param userName 62 | * @return 63 | */ 64 | List getUsersByName(@Param("name") String userName); 65 | 66 | /** 67 | * 获取所有user 68 | * @return 69 | */ 70 | List getAllUsers(); 71 | 72 | /** 73 | * 使用mybatis自带的RowBounds来分页(这个不推荐使用,因为是查询出所有的后在内存中进行分页) 74 | * @param rowBounds 75 | * @return 76 | */ 77 | List getUserByRowBounds(RowBounds rowBounds); 78 | 79 | /** 80 | * 使用自定义插件PagePlugin来分页获取user 81 | * @return 82 | */ 83 | List getUserByPage(MyPage myPage); 84 | 85 | List getUserByPageParam(@Param("pageNum") int pageNum, @Param("pageSize") int pageSize, @Param("countSql") boolean countSql); 86 | } 87 | -------------------------------------------------------------------------------- /mybatis-base/src/main/java/com/github/base/resulthandler/UserResultHandler.java: -------------------------------------------------------------------------------- 1 | package com.github.base.resulthandler; 2 | 3 | import com.github.base.bean.User; 4 | import org.apache.ibatis.session.ResultContext; 5 | import org.apache.ibatis.session.ResultHandler; 6 | 7 | /** 8 | * User: benjamin.wuhaixu 9 | * Date: 2018-02-05 10 | * Time: 5:29 pm 11 | */ 12 | public class UserResultHandler implements ResultHandler { 13 | @Override 14 | public void handleResult(ResultContext resultContext) { 15 | System.out.println(resultContext.getResultObject()); 16 | System.out.println(resultContext.getResultCount()); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /mybatis-base/src/main/java/com/github/base/typeHandler/MySexTypeHandler.java: -------------------------------------------------------------------------------- 1 | package com.github.base.typeHandler; 2 | 3 | import com.github.base.bean.SEX; 4 | import org.apache.ibatis.type.JdbcType; 5 | import org.apache.ibatis.type.TypeHandler; 6 | 7 | import java.sql.CallableStatement; 8 | import java.sql.PreparedStatement; 9 | import java.sql.ResultSet; 10 | import java.sql.SQLException; 11 | 12 | /** 13 | * User: 吴海旭 14 | * Date: 2017-06-13 15 | * Time: 下午7:53 16 | */ 17 | public class MySexTypeHandler implements TypeHandler { 18 | @Override 19 | public void setParameter(PreparedStatement ps, int i, SEX sex, JdbcType jdbcType) throws SQLException { 20 | if (sex == null) { 21 | ps.setInt(i, SEX.MALE.getCode()); 22 | } else { 23 | ps.setInt(i, sex.getCode()); 24 | } 25 | } 26 | 27 | @Override 28 | public SEX getResult(ResultSet rs, String s) throws SQLException { 29 | int code = rs.getInt(s); 30 | return SEX.fromCode(code); 31 | } 32 | 33 | @Override 34 | public SEX getResult(ResultSet rs, int i) throws SQLException { 35 | int code = rs.getInt(i); 36 | return SEX.fromCode(code); 37 | } 38 | 39 | @Override 40 | public SEX getResult(CallableStatement cs, int i) throws SQLException { 41 | int code = cs.getInt(i); 42 | return SEX.fromCode(code); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /mybatis-base/src/main/java/com/github/base/util/JSONUtil.java: -------------------------------------------------------------------------------- 1 | package com.github.base.util; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.alibaba.fastjson.serializer.SerializerFeature; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * User: 吴海旭 10 | * Date: 2017-06-29 11 | * Time: 下午1:21 12 | */ 13 | public class JSONUtil { 14 | 15 | public static String bean2Json(Object bean) throws RuntimeException{ 16 | return JSON.toJSONString(bean, SerializerFeature.WriteMapNullValue, SerializerFeature.WriteDateUseDateFormat); 17 | } 18 | 19 | public static T json2Bean(String json, Class clazz) throws RuntimeException{ 20 | return JSON.parseObject(json, clazz); 21 | } 22 | 23 | public static List json2List(String json, Class clazz) throws RuntimeException{ 24 | return JSON.parseArray(json, clazz); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /mybatis-base/src/main/java/com/github/base/util/PrintUtil.java: -------------------------------------------------------------------------------- 1 | package com.github.base.util; 2 | 3 | import org.slf4j.Logger; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * User: 吴海旭 9 | * Date: 2017-06-24 10 | * Time: 下午1:21 11 | */ 12 | public class PrintUtil { 13 | 14 | public static void printList(List list, Logger logger) { 15 | for (Object object : list) { 16 | logger.info(object.toString()); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /mybatis-base/src/main/java/com/github/base/util/ReflectUtil.java: -------------------------------------------------------------------------------- 1 | package com.github.base.util; 2 | 3 | import java.lang.reflect.Field; 4 | 5 | /** 6 | * User: 吴海旭 7 | * Date: 2017-06-17 8 | * Time: 上午11:27 9 | */ 10 | public class ReflectUtil { 11 | 12 | /** 13 | * 利用反射获取指定对象的指定属性 14 | * @param obj 目标对象 15 | * @param fieldName 目标属性 16 | * @return 目标属性的值 17 | */ 18 | public static Object getFieldValue(Object obj, String fieldName) { 19 | Object result = null; 20 | Field field = getField(obj, fieldName); 21 | if (field != null) { 22 | field.setAccessible(true); 23 | try { 24 | result = field.get(obj); 25 | } catch (IllegalArgumentException e) { 26 | e.printStackTrace(); 27 | } catch (IllegalAccessException e) { 28 | e.printStackTrace(); 29 | } 30 | } 31 | return result; 32 | } 33 | 34 | /** 35 | * 利用反射获取指定对象里面的指定属性 36 | * @param obj 目标对象 37 | * @param fieldName 目标属性 38 | * @return 目标字段 39 | */ 40 | private static Field getField(Object obj, String fieldName) { 41 | Field field = null; 42 | for (Class clazz=obj.getClass(); clazz != Object.class; clazz=clazz.getSuperclass()) { 43 | try { 44 | field = clazz.getDeclaredField(fieldName); 45 | break; 46 | } catch (NoSuchFieldException e) { 47 | //这里不用做处理,子类没有该字段可能对应的父类有,都没有就返回null。 48 | } 49 | } 50 | return field; 51 | } 52 | 53 | /** 54 | * 利用反射设置指定对象的指定属性为指定的值 55 | * @param obj 目标对象 56 | * @param fieldName 目标属性 57 | * @param fieldValue 目标值 58 | */ 59 | public static void setFieldValue(Object obj, String fieldName, 60 | Object fieldValue) { 61 | Field field = ReflectUtil.getField(obj, fieldName); 62 | if (field != null) { 63 | try { 64 | field.setAccessible(true); 65 | field.set(obj, fieldValue); 66 | } catch (IllegalArgumentException e) { 67 | e.printStackTrace(); 68 | } catch (IllegalAccessException e) { 69 | e.printStackTrace(); 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /mybatis-base/src/main/java/com/github/base/util/TimeUtils.java: -------------------------------------------------------------------------------- 1 | package com.github.base.util; 2 | 3 | import java.text.ParseException; 4 | import java.text.SimpleDateFormat; 5 | import java.util.Calendar; 6 | import java.util.Date; 7 | 8 | /** 9 | * User: 吴海旭 10 | * Date: 2017-10-31 11 | * Time: 下午3:40 12 | */ 13 | public class TimeUtils { 14 | public static final String yyyyMMdd = "yyyyMMdd"; 15 | public static final String yyyy_MM_dd = "yyyy-MM-dd HH:mm:ss"; 16 | public static final String COMMON_FORMAT = "yyyy-MM-dd HH:mm:ss"; 17 | public static final String yyyyMMddHHmmss = "yyyyMMddHHmmss"; 18 | 19 | public static long betweenMills(Date fromDate, Date toDate) { 20 | return toDate.getTime() - fromDate.getTime(); 21 | } 22 | 23 | public static Date parseDate(String format, String dateStr) throws ParseException { 24 | SimpleDateFormat sdf = new SimpleDateFormat(format); 25 | return sdf.parse(dateStr); 26 | } 27 | 28 | public static String formatDate(String format, Date date) { 29 | SimpleDateFormat sdf = new SimpleDateFormat(format); 30 | return sdf.format(date); 31 | } 32 | public static String formatDateNow() { 33 | SimpleDateFormat sdf = new SimpleDateFormat(yyyyMMddHHmmss); 34 | return sdf.format(new Date()); 35 | } 36 | 37 | public static String formatDateLimitInHours(Date date,int hours){ 38 | Calendar Cal = Calendar.getInstance(); 39 | Cal.setTime(new Date()); 40 | Cal.add(Calendar.HOUR_OF_DAY,hours*-1); 41 | return formatDate(yyyy_MM_dd,Cal.getTime()); 42 | } 43 | 44 | public static void main(String[] args) { 45 | /* Calendar fromDate = Calendar.getInstance(); 46 | fromDate.set(Calendar.MONTH, Calendar.OCTOBER); 47 | fromDate.set(Calendar.DAY_OF_MONTH, 15); 48 | fromDate.set(Calendar.HOUR_OF_DAY, 0); 49 | fromDate.set(Calendar.MINUTE, 0); 50 | fromDate.set(Calendar.SECOND, 0); 51 | System.out.println(fromDate.getTime()); 52 | Calendar toDate = Calendar.getInstance(); 53 | toDate.set(Calendar.MONTH, Calendar.OCTOBER); 54 | toDate.set(Calendar.DAY_OF_MONTH, 16); 55 | toDate.set(Calendar.HOUR_OF_DAY, 0); 56 | toDate.set(Calendar.MINUTE, 0); 57 | toDate.set(Calendar.SECOND, 0); 58 | System.out.println(toDate.getTime()); 59 | System.out.println(betweenDays(fromDate.getTime(), toDate.getTime())); 60 | System.out.println(betweenMills(fromDate.getTime(), toDate.getTime()));*/ 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /mybatis-base/src/main/resources/dbConfig.properties: -------------------------------------------------------------------------------- 1 | mysql.driver=com.mysql.cj.jdbc.Driver 2 | mysql.url=jdbc:mysql://localhost/mybatis?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC 3 | mysql.userName=root 4 | mysql.password=123456 5 | 6 | mysql.initialSize=2 7 | mysql.maxActive=20 8 | mysql.maxIdle=20 9 | mysql.minIdle=0 10 | mysql.poolPreparedStatements=true 11 | mysql.defaultAutoCommit=false -------------------------------------------------------------------------------- /mybatis-base/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Mybatis 4 | 5 | 6 | 7 | 8 | 9 | ${LOG_PATTEN} 10 | 11 | 12 | DEBUG 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /mybatis-base/src/main/resources/mapper/RoleMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 20 | -------------------------------------------------------------------------------- /mybatis-base/src/main/resources/mapper/UserMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | ${prefix}.id, ${prefix}.user_name, ${prefix}.sex, ${prefix}.role_id 11 | 12 | 13 | id, user_name, sex, role_id 14 | 15 | 16 | 17 | 18 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | INSERT INTO 49 | cf_user (user_name, sex, role_id) 50 | VALUES 51 | (#{userName}, #{sex, typeHandler=com.github.base.typeHandler.MySexTypeHandler, javaType=sex, jdbcType=INTEGER}, #{roleId}) 52 | 53 | 54 | 55 | INSERT INTO 56 | cf_user (user_name, sex, role_id) 57 | VALUES 58 | 59 | (#{item.userName}, #{item.sex, typeHandler=com.github.base.typeHandler.MySexTypeHandler, javaType=sex, jdbcType=INTEGER}, #{item.roleId}) 60 | 61 | 62 | 63 | 73 | 74 | 81 | 82 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 111 | 112 | 119 | 120 | 127 | 128 | 129 | update cf_user 130 | 131 | 132 | user_name = #{userName}, 133 | 134 | 135 | sex = #{sex, javaType=com.github.base.bean.SEX, jdbcType=INTEGER, typeHandler=com.github.base.typeHandler.MySexTypeHandler}, 136 | 137 | 138 | role_id = #{roleId}, 139 | 140 | 141 | 142 | 143 | and id = #{id} 144 | 145 | 146 | 147 | 148 | 149 | DELETE FROM 150 | cf_user 151 | 152 | 153 | AND id = #{id} 154 | 155 | 156 | 157 | -------------------------------------------------------------------------------- /mybatis-base/src/main/resources/sql/run.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Navicat MySQL Data Transfer 3 | 4 | Source Server : localhost 5 | Source Server Version : 50718 6 | Source Host : localhost:3306 7 | Source Database : mybatis 8 | 9 | Target Server Type : MYSQL 10 | Target Server Version : 50718 11 | File Encoding : 65001 12 | 13 | Date: 2017-06-24 14:24:24 14 | */ 15 | 16 | SET FOREIGN_KEY_CHECKS=0; 17 | 18 | -- ---------------------------- 19 | -- Table structure for cf_order 20 | -- ---------------------------- 21 | DROP TABLE IF EXISTS `cf_order`; 22 | CREATE TABLE `cf_order` ( 23 | `id` bigint(20) NOT NULL AUTO_INCREMENT, 24 | `order_id` varchar(255) DEFAULT NULL, 25 | `order_name` varchar(255) DEFAULT NULL, 26 | `uid` int(11) DEFAULT NULL, 27 | PRIMARY KEY (`id`) 28 | ) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8; 29 | 30 | -- ---------------------------- 31 | -- Records of cf_order 32 | -- ---------------------------- 33 | INSERT INTO `cf_order` VALUES ('1', 'e71346c4-58a4-11e7-907b-a6006ad3dba0', '衣服', '1'); 34 | INSERT INTO `cf_order` VALUES ('2', '3b518ac0-58a5-11e7-907b-a6006ad3dba0', '珠宝', '1'); 35 | INSERT INTO `cf_order` VALUES ('3', '59289b60-58a5-11e7-907b-a6006ad3dba0', '箱包', '3'); 36 | INSERT INTO `cf_order` VALUES ('4', '6218b020-58a5-11e7-907b-a6006ad3dba0', '花卉', '10'); 37 | INSERT INTO `cf_order` VALUES ('5', '66445cc6-58a5-11e7-907b-a6006ad3dba0', '3c', '11'); 38 | INSERT INTO `cf_order` VALUES ('6', '6a16dd1a-58a5-11e7-907b-a6006ad3dba0', '驾校', '2'); 39 | INSERT INTO `cf_order` VALUES ('7', '6e0186dc-58a5-11e7-907b-a6006ad3dba0', '自行车', '5'); 40 | INSERT INTO `cf_order` VALUES ('8', '71dd15be-58a5-11e7-907b-a6006ad3dba0', '汽车', '2'); 41 | INSERT INTO `cf_order` VALUES ('9', '74f26e8e-58a5-11e7-907b-a6006ad3dba0', '手表', '13'); 42 | INSERT INTO `cf_order` VALUES ('10', '78077aec-58a5-11e7-907b-a6006ad3dba0', '厨具', '11'); 43 | INSERT INTO `cf_order` VALUES ('11', '7da6d1dc-58a5-11e7-907b-a6006ad3dba0', '床上用品', '10'); 44 | INSERT INTO `cf_order` VALUES ('12', '814a4d46-58a5-11e7-907b-a6006ad3dba0', '鞋子', '8'); 45 | INSERT INTO `cf_order` VALUES ('13', '84d99f02-58a5-11e7-907b-a6006ad3dba0', '书桌', '5'); 46 | INSERT INTO `cf_order` VALUES ('14', '884ce34c-58a5-11e7-907b-a6006ad3dba0', '台灯', '1'); 47 | INSERT INTO `cf_order` VALUES ('15', '8bc4b54a-58a5-11e7-907b-a6006ad3dba0', '纸巾', '12'); 48 | INSERT INTO `cf_order` VALUES ('16', '8f72a210-58a5-11e7-907b-a6006ad3dba0', '电脑', '11'); 49 | 50 | -- ---------------------------- 51 | -- Table structure for cf_role 52 | -- ---------------------------- 53 | DROP TABLE IF EXISTS `cf_role`; 54 | CREATE TABLE `cf_role` ( 55 | `id` bigint(20) NOT NULL AUTO_INCREMENT, 56 | `role_name` varchar(255) DEFAULT NULL, 57 | PRIMARY KEY (`id`) 58 | ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8; 59 | 60 | -- ---------------------------- 61 | -- Records of cf_role 62 | -- ---------------------------- 63 | INSERT INTO `cf_role` VALUES ('1', '管理员'); 64 | INSERT INTO `cf_role` VALUES ('2', '客服'); 65 | INSERT INTO `cf_role` VALUES ('3', '开发'); 66 | 67 | -- ---------------------------- 68 | -- Table structure for cf_user 69 | -- ---------------------------- 70 | DROP TABLE IF EXISTS `cf_user`; 71 | CREATE TABLE `cf_user` ( 72 | `id` bigint(20) NOT NULL AUTO_INCREMENT, 73 | `user_name` varchar(255) DEFAULT NULL, 74 | `sex` int(255) DEFAULT NULL, 75 | `role_id` bigint(20) DEFAULT NULL, 76 | PRIMARY KEY (`id`) 77 | ) ENGINE=InnoDB AUTO_INCREMENT=65 DEFAULT CHARSET=utf8; 78 | 79 | -- ---------------------------- 80 | -- Records of cf_user 81 | -- ---------------------------- 82 | INSERT INTO `cf_user` VALUES ('1', 'Jack', '1', '1'); 83 | INSERT INTO `cf_user` VALUES ('2', 'Lucy', '2', '1'); 84 | INSERT INTO `cf_user` VALUES ('3', 'Sunny', '2', '3'); 85 | INSERT INTO `cf_user` VALUES ('4', 'Marshall', '1', '2'); 86 | INSERT INTO `cf_user` VALUES ('5', 'June', '2', '2'); 87 | INSERT INTO `cf_user` VALUES ('6', 'Benjamin', '1', '1'); 88 | INSERT INTO `cf_user` VALUES ('7', 'Caroline', '2', '1'); 89 | INSERT INTO `cf_user` VALUES ('8', 'Turos', '1', '3'); 90 | INSERT INTO `cf_user` VALUES ('9', 'Abns', '2', '2'); 91 | INSERT INTO `cf_user` VALUES ('10', 'Wasj', '1', '2'); 92 | INSERT INTO `cf_user` VALUES ('11', 'Fisher', '1', '1'); 93 | INSERT INTO `cf_user` VALUES ('12', 'Pors', '2', '2'); 94 | INSERT INTO `cf_user` VALUES ('13', 'Yons', '1', '3'); 95 | 96 | -- ---------------------------- 97 | -- Table structure for user_login 98 | -- ---------------------------- 99 | DROP TABLE IF EXISTS `user_login`; 100 | CREATE TABLE `user_login` ( 101 | `id` bigint(20) NOT NULL AUTO_INCREMENT, 102 | `username` varchar(32) NOT NULL, 103 | `logindate` datetime DEFAULT NULL, 104 | `loginip` varchar(16) DEFAULT NULL, 105 | PRIMARY KEY (`id`) 106 | ) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8; 107 | 108 | -- ---------------------------- 109 | -- Records of user_login 110 | -- ---------------------------- 111 | INSERT INTO `user_login` VALUES ('1', 'test1', '2014-10-11 12:00:00', '192.168.1.123'); 112 | INSERT INTO `user_login` VALUES ('2', 'test1', '2014-10-21 12:00:00', '192.168.1.123'); 113 | INSERT INTO `user_login` VALUES ('3', 'test1', '2014-10-21 14:00:00', '192.168.1.123'); 114 | INSERT INTO `user_login` VALUES ('4', 'test1', '2014-11-21 11:20:00', '192.168.1.123'); 115 | INSERT INTO `user_login` VALUES ('5', 'test1', '2014-11-21 13:00:00', '192.168.1.123'); 116 | INSERT INTO `user_login` VALUES ('6', 'test2', '2014-11-21 12:00:00', '192.168.1.123'); 117 | INSERT INTO `user_login` VALUES ('7', 'test2', '2014-11-21 12:00:00', '192.168.1.123'); 118 | INSERT INTO `user_login` VALUES ('8', 'test3', '2014-11-21 12:00:00', '192.168.1.123'); 119 | INSERT INTO `user_login` VALUES ('9', 'test4', '2014-11-21 12:00:00', '192.168.1.123'); 120 | INSERT INTO `user_login` VALUES ('10', 'test5', '2014-11-21 12:00:00', '192.168.1.123'); 121 | 122 | -- ---------------------------- 123 | -- Table structure for user_login2 124 | -- ---------------------------- 125 | DROP TABLE IF EXISTS `user_login2`; 126 | CREATE TABLE `user_login2` ( 127 | `id` bigint(20) NOT NULL AUTO_INCREMENT, 128 | `username` varchar(32) NOT NULL, 129 | `logindate` datetime DEFAULT NULL, 130 | `loginip` varchar(16) DEFAULT NULL, 131 | PRIMARY KEY (`id`) 132 | ) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8; 133 | 134 | -- ---------------------------- 135 | -- Records of user_login2 136 | -- ---------------------------- 137 | INSERT INTO `user_login2` VALUES ('1', 'test1', '2014-10-11 12:00:00', '192.168.1.123'); 138 | INSERT INTO `user_login2` VALUES ('2', 'test1', '2014-10-21 12:00:00', '192.168.1.123'); 139 | INSERT INTO `user_login2` VALUES ('3', 'test1', '2014-10-21 14:00:00', '192.168.1.123'); 140 | INSERT INTO `user_login2` VALUES ('4', 'test1', '2014-11-21 11:20:00', '192.168.1.123'); 141 | INSERT INTO `user_login2` VALUES ('5', 'test1', '2014-11-21 13:00:00', '192.168.1.123'); 142 | INSERT INTO `user_login2` VALUES ('6', 'test2', '2014-11-21 12:00:00', '192.168.1.123'); 143 | INSERT INTO `user_login2` VALUES ('7', 'test2', '2014-11-21 12:00:00', '192.168.1.123'); 144 | INSERT INTO `user_login2` VALUES ('8', 'test3', '2014-11-21 12:00:00', '192.168.1.123'); 145 | INSERT INTO `user_login2` VALUES ('9', 'test4', '2014-11-21 12:00:00', '192.168.1.123'); 146 | INSERT INTO `user_login2` VALUES ('10', 'test5', '2014-11-21 12:00:00', '192.168.1.123'); 147 | -------------------------------------------------------------------------------- /mybatis-base/src/main/resources/sql/student.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Navicat MySQL Data Transfer 3 | 4 | Source Server : local 5 | Source Server Version : 50634 6 | Source Host : localhost:3306 7 | Source Database : mybatis 8 | 9 | Target Server Type : MYSQL 10 | Target Server Version : 50634 11 | File Encoding : 65001 12 | 13 | Date: 2017-06-28 19:04:55 14 | */ 15 | 16 | SET FOREIGN_KEY_CHECKS=0; 17 | 18 | -- ---------------------------- 19 | -- Table structure for student 20 | -- ---------------------------- 21 | DROP TABLE IF EXISTS `student`; 22 | CREATE TABLE `student` ( 23 | `id` bigint(11) NOT NULL AUTO_INCREMENT, 24 | `name` varchar(45) DEFAULT NULL, 25 | PRIMARY KEY (`id`) 26 | ) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8; 27 | -------------------------------------------------------------------------------- /mybatis-core/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | mybatis 5 | com.github 6 | 1.0-SNAPSHOT 7 | 8 | 4.0.0 9 | 10 | mybatis-core 11 | jar 12 | 13 | mybatis-core 14 | http://maven.apache.org 15 | 16 | 17 | 18 | com.github 19 | mybatis-base 20 | 1.0-SNAPSHOT 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /mybatis-core/src/main/java/com/github/core/builder/CacheBuilder.java: -------------------------------------------------------------------------------- 1 | package com.github.core.builder; 2 | 3 | import com.github.base.bean.User; 4 | import com.github.base.mapper.UserMapper; 5 | import com.github.base.util.JSONUtil; 6 | import com.github.core.util.MyBatisConfigHelper; 7 | import org.apache.commons.beanutils.BeanUtils; 8 | import org.apache.ibatis.session.SqlSession; 9 | import org.apache.ibatis.session.SqlSessionFactory; 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | 13 | import java.lang.reflect.InvocationTargetException; 14 | 15 | /** 16 | * User: 吴海旭 17 | * Date: 2017-06-24 18 | * Time: 下午2:50 19 | */ 20 | public class CacheBuilder { 21 | 22 | private Logger logger = LoggerFactory.getLogger(CacheBuilder.class); 23 | 24 | /** 25 | * 一级缓存:sqlSession级别的缓存 26 | * 同一个sqlSession执行相同的mapper的语句,传入参数相同,使用缓存的结果。 27 | * 不同的sqlSession会再次发出sql语句。 28 | * 29 | * 二级缓存:sqlSessionFactory级别的缓存,默认不开启 30 | * 开启二级缓存需要POJO必须是可序列化的(implements Serializable),而且在mapper文件中必须执行 31 | * 二级缓存只要是同一个sqlSessionFactory执行相同的mapper语句,传入的参数相同,都会使用缓存的结果 32 | */ 33 | private void testOneAndTwoLevelCache() { 34 | SqlSessionFactory sqlSessionFactory = MyBatisConfigHelper.getSqlSessionFactory(); 35 | SqlSession sqlSession1 = sqlSessionFactory.openSession(); 36 | UserMapper mapper = sqlSession1.getMapper(UserMapper.class); 37 | User user = mapper.getUserByUserId(1L); 38 | logger.info("使用同一个sqlSession再执行一次"); 39 | User user2 = mapper.getUserByUserId(1L); 40 | sqlSession1.commit(); 41 | 42 | logger.info("现在创建一个新的sqlSession再执行一次"); 43 | SqlSession sqlSession2 = sqlSessionFactory.openSession(); 44 | UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class); 45 | User user3 = mapper2.getUserByUserId(1L); 46 | sqlSession2.commit(); 47 | 48 | sqlSession1.close(); 49 | sqlSession2.close(); 50 | } 51 | 52 | /** 53 | * 不同的SqlSession会产生脏数据问题 54 | * @throws InvocationTargetException 55 | * @throws IllegalAccessException 56 | */ 57 | private void testMultiSqlSessionIsolation() throws InvocationTargetException, IllegalAccessException { 58 | SqlSessionFactory sqlSessionFactory = MyBatisConfigHelper.getSqlSessionFactory(); 59 | SqlSession sqlSession1 = sqlSessionFactory.openSession(); 60 | SqlSession sqlSession2 = sqlSessionFactory.openSession(); 61 | UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class); 62 | UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class); 63 | 64 | User user = mapper1.getUserByUserId(2L); 65 | 66 | logger.info("user1: " + JSONUtil.bean2Json(user)); 67 | User user2 = new User(); 68 | BeanUtils.copyProperties(user2, user); 69 | user2.setUserName("Lucy_update"); 70 | 71 | logger.info("user2: " + JSONUtil.bean2Json(user2)); 72 | mapper2.update(user2); 73 | sqlSession2.commit(); 74 | 75 | User user3 = mapper1.getUserByUserId(2L); 76 | logger.info("user3: " + JSONUtil.bean2Json(user3)); 77 | sqlSession1.commit(); 78 | } 79 | 80 | public static void main(String[] args) throws InvocationTargetException, IllegalAccessException { 81 | // new CacheBuilder().testOneAndTwoLevelCache(); 82 | new CacheBuilder().testMultiSqlSessionIsolation(); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /mybatis-core/src/main/java/com/github/core/builder/MyBatisCoreBuilder.java: -------------------------------------------------------------------------------- 1 | package com.github.core.builder; 2 | 3 | import com.github.base.bean.MyPage; 4 | import com.github.base.bean.SEX; 5 | import com.github.base.bean.User; 6 | import com.github.base.mapper.UserMapper; 7 | import com.github.base.resulthandler.UserResultHandler; 8 | import com.github.base.util.PrintUtil; 9 | import com.github.core.util.MyBatisConfigHelper; 10 | import org.apache.ibatis.session.*; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | import java.util.*; 14 | 15 | /** 16 | * User: 吴海旭 17 | * Date: 2017-06-24 18 | * Time: 下午1:23 19 | */ 20 | public class MyBatisCoreBuilder { 21 | 22 | private Logger logger = LoggerFactory.getLogger(MyBatisCoreBuilder.class); 23 | 24 | private void testUserMapperInsert() { 25 | SqlSession sqlSession = MyBatisConfigHelper.getSqlSession(true); 26 | UserMapper mapper = sqlSession.getMapper(UserMapper.class); 27 | User user = new User(); 28 | user.setUserName("张三"); 29 | user.setSex(SEX.MALE); 30 | user.setRoleId(1L); 31 | int insert = mapper.insert(user); 32 | if (insert == 1) { 33 | logger.info("插入成功, id=" + user.getId()); 34 | } else { 35 | logger.info("插入失败, insert=" + insert); 36 | } 37 | } 38 | 39 | private void testUserMapperInsertMulti() { 40 | SqlSession sqlSession = MyBatisConfigHelper.getSqlSession(); 41 | UserMapper mapper = sqlSession.getMapper(UserMapper.class); 42 | for (int i = 0; i < 30; ++i) { 43 | User user = new User(); 44 | user.setUserName("张三" + i); 45 | if (i % 2 == 0) { 46 | user.setSex(SEX.MALE); 47 | } else { 48 | user.setSex(SEX.FEMALE); 49 | } 50 | user.setRoleId(1L); 51 | mapper.insert(user); 52 | } 53 | sqlSession.commit(); 54 | } 55 | 56 | private void testUserMapperSelect1() { 57 | SqlSession sqlSession = MyBatisConfigHelper.getSqlSession(); 58 | UserMapper mapper = sqlSession.getMapper(UserMapper.class); 59 | User user = mapper.getUserByUserId(2L); 60 | logger.info(user.toString()); 61 | } 62 | 63 | private void testUserMapperSelect2() { 64 | SqlSession sqlSession = MyBatisConfigHelper.getSqlSession(); 65 | UserMapper mapper = sqlSession.getMapper(UserMapper.class); 66 | List userList = mapper.getUsersByName("Benjamin"); 67 | PrintUtil.printList(userList, logger); 68 | } 69 | 70 | private void testUserMapperSelect3() { 71 | SqlSession sqlSession = MyBatisConfigHelper.getSqlSession(); 72 | UserMapper mapper = sqlSession.getMapper(UserMapper.class); 73 | List userList = mapper.getAllUsers(); 74 | PrintUtil.printList(userList, logger); 75 | } 76 | 77 | private void testUserMapperSelect4() { 78 | SqlSession sqlSession = MyBatisConfigHelper.getSqlSession(); 79 | UserMapper mapper = sqlSession.getMapper(UserMapper.class); 80 | List userList = mapper.getUserByRowBounds(new RowBounds(0, 5)); 81 | PrintUtil.printList(userList, logger); 82 | } 83 | 84 | private void testUserMapperSelect5() { 85 | SqlSession sqlSession = MyBatisConfigHelper.getSqlSession(); 86 | UserMapper mapper = sqlSession.getMapper(UserMapper.class); 87 | MyPage myPage = new MyPage<>(); 88 | myPage.setPageNo(2); 89 | myPage.setPageSize(5); 90 | List userList = mapper.getUserByPage(myPage); 91 | PrintUtil.printList(userList, logger); 92 | } 93 | 94 | private void testUserMapperSelect6() { 95 | SqlSession sqlSession = MyBatisConfigHelper.getSqlSession(); 96 | UserMapper mapper = sqlSession.getMapper(UserMapper.class); 97 | mapper.getUserByUserIdAndResultHandler(new UserResultHandler()); 98 | } 99 | 100 | private void testUserMapperUpdate() { 101 | SqlSession sqlSession = MyBatisConfigHelper.getSqlSession(true); 102 | UserMapper mapper = sqlSession.getMapper(UserMapper.class); 103 | User user = new User(); 104 | user.setId(6L); 105 | user.setUserName("Benjamin2"); 106 | mapper.update(user); 107 | } 108 | 109 | private void testUserMapperDelete() { 110 | SqlSession sqlSession = MyBatisConfigHelper.getSqlSession(true); 111 | UserMapper mapper = sqlSession.getMapper(UserMapper.class); 112 | mapper.delete(1L); 113 | } 114 | 115 | // batch方式花费:10869ms 116 | private void testUserMapperBatch() { 117 | SqlSession sqlSession = MyBatisConfigHelper.getSqlSession(ExecutorType.BATCH); 118 | UserMapper mapper = sqlSession.getMapper(UserMapper.class); 119 | long begin = System.currentTimeMillis(); 120 | for (int i = 0; i < 100; i++) { 121 | for (int j = 0; j < 1000; j++) { 122 | User user = new User(); 123 | user.setUserName("new名字" + j); 124 | user.setSex(SEX.MALE); 125 | user.setRoleId(1L); 126 | mapper.insert(user); 127 | } 128 | sqlSession.commit(); 129 | } 130 | long end = System.currentTimeMillis(); 131 | System.out.println("batch方式花费:" + (end - begin) + "ms"); 132 | } 133 | 134 | // batch方式花费:10388ms 135 | private void testUserMapperBatch2() { 136 | SqlSession sqlSession = MyBatisConfigHelper.getSqlSession(ExecutorType.BATCH); 137 | UserMapper mapper = sqlSession.getMapper(UserMapper.class); 138 | long begin = System.currentTimeMillis(); 139 | for (int i = 0; i < 100; i++) { 140 | for (int j = 0; j < 1000; j++) { 141 | User user = new User(); 142 | user.setUserName("new名字" + j); 143 | user.setSex(SEX.MALE); 144 | user.setRoleId(1L); 145 | mapper.insert(user); 146 | } 147 | mapper.flush(); 148 | } 149 | sqlSession.commit(); 150 | long end = System.currentTimeMillis(); 151 | System.out.println("batch方式花费:" + (end - begin) + "ms"); 152 | } 153 | 154 | // mapper文件for循环方式花费:3110ms 155 | private void testInsertBatch() { 156 | SqlSession sqlSession = MyBatisConfigHelper.getSqlSession(true); 157 | UserMapper mapper = sqlSession.getMapper(UserMapper.class); 158 | long begin = System.currentTimeMillis(); 159 | for (int i = 0; i < 100; i++) { 160 | List users = new ArrayList<>(); 161 | for (int j = 0; j < 1000; j++) { 162 | User user = new User(); 163 | user.setUserName("new2名字" + j); 164 | user.setSex(SEX.FEMALE); 165 | user.setRoleId(1L); 166 | users.add(user); 167 | } 168 | mapper.insertBatch(users); 169 | } 170 | long end = System.currentTimeMillis(); 171 | System.out.println("mapper文件for循环方式花费:" + (end - begin) + "ms"); 172 | } 173 | 174 | // mapper文件for循环方式花费:33705ms 175 | private void testInsert() { 176 | SqlSession sqlSession = MyBatisConfigHelper.getSqlSession(true); 177 | UserMapper mapper = sqlSession.getMapper(UserMapper.class); 178 | long begin = System.currentTimeMillis(); 179 | for (int i = 0; i < 100000; i++) { 180 | User user = new User(); 181 | user.setUserName("new2名字" + i); 182 | user.setSex(SEX.FEMALE); 183 | user.setRoleId(1L); 184 | mapper.insert(user); 185 | } 186 | long end = System.currentTimeMillis(); 187 | System.out.println("mapper文件for循环方式花费:" + (end - begin) + "ms"); 188 | } 189 | 190 | public static void main(String[] args) { 191 | MyBatisCoreBuilder builder = new MyBatisCoreBuilder(); 192 | // builder.testUserMapperInsert(); 193 | // builder.testUserMapperInsertMulti(); 194 | // builder.testUserMapperSelect1(); 195 | // builder.testUserMapperSelect2(); 196 | // builder.testUserMapperSelect3(); 197 | // builder.testUserMapperSelect4(); 198 | // builder.testUserMapperSelect5(); 199 | // builder.testUserMapperUpdate(); 200 | // builder.testUserMapperDelete(); 201 | // builder.testUserMapperSelect6(); 202 | // builder.testUserMapperBatch(); 203 | builder.testUserMapperBatch2(); 204 | // builder.testInsertBatch(); 205 | // builder.testInsert(); 206 | } 207 | } 208 | -------------------------------------------------------------------------------- /mybatis-core/src/main/java/com/github/core/builder/SqlPrintBuilder.java: -------------------------------------------------------------------------------- 1 | package com.github.core.builder; 2 | 3 | import com.github.base.util.SqlHelper; 4 | import com.github.core.util.MyBatisConfigHelper; 5 | import org.apache.ibatis.session.SqlSession; 6 | 7 | /** 8 | * User: 吴海旭 9 | * Date: 2017-06-24 10 | * Time: 下午3:07 11 | */ 12 | public class SqlPrintBuilder { 13 | 14 | public static void main(String[] args) { 15 | SqlSession sqlSession = null; 16 | try { 17 | sqlSession = MyBatisConfigHelper.getSqlSession(true); 18 | 19 | // String mapperSql = SqlHelper.getMapperSql(sqlSession, UserMapper.class, "getUsersByName", "abc"); 20 | // System.out.println(mapperSql); 21 | 22 | // String mapperSql2 = SqlHelper.getMapperSql(sqlSession, "com.github.base.mapper.UserMapper.getUsersByName", "abc"); 23 | // System.out.println(mapperSql2); 24 | 25 | // String mapperSql3 = SqlHelper.getMapperSql(sqlSession.getMapper(UserMapper.class), "getUsersByName", "abc"); 26 | // System.out.println(mapperSql3); 27 | 28 | String namespaceSql4 = SqlHelper.getNamespaceSql(sqlSession, "com.github.base.mapper.UserMapper.getUsersByName", "abc"); 29 | System.out.println(namespaceSql4); 30 | } catch (Exception e) { 31 | e.printStackTrace(); 32 | } finally { 33 | if (sqlSession != null) { 34 | sqlSession.close(); 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /mybatis-core/src/main/java/com/github/core/cache/MyCache.java: -------------------------------------------------------------------------------- 1 | package com.github.core.cache; 2 | 3 | import org.apache.ibatis.cache.Cache; 4 | 5 | import java.util.concurrent.ConcurrentHashMap; 6 | import java.util.concurrent.locks.ReadWriteLock; 7 | import java.util.concurrent.locks.ReentrantReadWriteLock; 8 | 9 | /** 10 | * User: 吴海旭 11 | * Date: 2017-06-13 12 | * Time: 下午10:20 13 | */ 14 | public class MyCache implements Cache { 15 | 16 | private ReadWriteLock lock = new ReentrantReadWriteLock(); 17 | private ConcurrentHashMap cache = new ConcurrentHashMap(); 18 | private String id; 19 | 20 | public MyCache() { 21 | } 22 | 23 | public MyCache(String id) { 24 | this.id = id; 25 | } 26 | 27 | @Override 28 | public String getId() { 29 | return id; 30 | } 31 | 32 | @Override 33 | public void putObject(Object key, Object value) { 34 | System.out.println("putObject---key:" + key); 35 | cache.put(key, value); 36 | } 37 | 38 | @Override 39 | public Object getObject(Object key) { 40 | System.out.println("getObject---key:" + key); 41 | return cache.get(key); 42 | } 43 | 44 | @Override 45 | public Object removeObject(Object key) { 46 | System.out.println("remove:" + key); 47 | return cache.remove(key); 48 | } 49 | 50 | @Override 51 | public void clear() { 52 | cache.clear(); 53 | } 54 | 55 | @Override 56 | public int getSize() { 57 | System.out.println("getsize"); 58 | return cache.size(); 59 | } 60 | 61 | @Override 62 | public ReadWriteLock getReadWriteLock() { 63 | return lock; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /mybatis-core/src/main/java/com/github/core/plugin/PagePlugin.java: -------------------------------------------------------------------------------- 1 | package com.github.core.plugin; 2 | 3 | import com.github.base.bean.MyPage; 4 | import com.github.base.util.ReflectUtil; 5 | import org.apache.ibatis.executor.parameter.ParameterHandler; 6 | import org.apache.ibatis.executor.statement.RoutingStatementHandler; 7 | import org.apache.ibatis.executor.statement.StatementHandler; 8 | import org.apache.ibatis.mapping.BoundSql; 9 | import org.apache.ibatis.mapping.MappedStatement; 10 | import org.apache.ibatis.mapping.ParameterMapping; 11 | import org.apache.ibatis.plugin.*; 12 | import org.apache.ibatis.scripting.defaults.DefaultParameterHandler; 13 | 14 | import java.sql.Connection; 15 | import java.sql.PreparedStatement; 16 | import java.sql.ResultSet; 17 | import java.sql.SQLException; 18 | import java.util.List; 19 | import java.util.Properties; 20 | 21 | /** 22 | * User: 吴海旭 23 | * Date: 2017-06-17 24 | * Time: 上午11:15 25 | * 26 | * 分页拦截器,用于拦截需要进行分页查询的操作,然后对其进行分页处理。 27 | * 利用拦截器实现Mybatis分页的原理: 28 | * 要利用JDBC对数据库进行操作就必须要有一个对应的Statement对象,Mybatis在执行Sql语句前就会产生一个包含Sql语句的Statement对象,而且对应的Sql语句 是在Statement之前产生的,所以我们就可以在它生成Statement之前对用来生成Statement的Sql语句下手。在Mybatis中Statement语句是通过RoutingStatementHandler对象的 prepare方法生成的。所以利用拦截器实现Mybatis分页的一个思路就是拦截StatementHandler接口的prepare方法,然后在拦截器方法中把Sql语句改成对应的分页查询Sql语句,之后再调用 29 | * StatementHandler对象的prepare方法,即调用invocation.proceed()。 30 | * 对于分页而言,在拦截器里面我们还需要做的一个操作就是统计满足当前条件的记录一共有多少,这是通过获取到了原始的Sql语句后,把它改为对应的统计语句再利用Mybatis封装好的参数和设 31 | * 置参数的功能把Sql语句中的参数进行替换,之后再执行查询记录数的Sql语句进行总记录数的统计。 32 | */ 33 | @Intercepts({ 34 | @Signature(method = "prepare", type = StatementHandler.class, args = {Connection.class, Integer.class}) 35 | }) 36 | public class PagePlugin implements Interceptor { 37 | 38 | // 数据库类型,不同数据库不同的分页方法 39 | private String databaseType; 40 | 41 | /** 42 | * 拦截后要执行的方法 43 | * @param invocation 44 | * @return 45 | * @throws Throwable 46 | */ 47 | @Override 48 | public Object intercept(Invocation invocation) throws Throwable { 49 | RoutingStatementHandler routingStatementHandler = (RoutingStatementHandler) invocation.getTarget(); 50 | StatementHandler delegate = (StatementHandler) ReflectUtil.getFieldValue(routingStatementHandler, "delegate"); 51 | BoundSql boundSql = delegate.getBoundSql(); 52 | //拿到当前绑定Sql的参数对象,就是我们在调用对应的Mapper映射语句时所传入的参数对象 53 | Object obj = boundSql.getParameterObject(); 54 | //这里我们简单的通过传入的是Page对象就认定它是需要进行分页操作的。 55 | if (obj instanceof MyPage) { 56 | MyPage myPage = (MyPage) obj; 57 | //通过反射获取delegate父类BaseStatementHandler的mappedStatement属性 58 | MappedStatement mappedStatement = (MappedStatement)ReflectUtil.getFieldValue(delegate, "mappedStatement"); 59 | //拦截到的prepare方法参数是一个Connection对象 60 | Connection connection = (Connection)invocation.getArgs()[0]; 61 | //获取当前要执行的Sql语句,也就是我们直接在Mapper映射语句中写的Sql语句 62 | String sql = boundSql.getSql(); 63 | //给当前的page参数对象设置总记录数 64 | this.setTotalRecord(myPage, 65 | mappedStatement, connection); 66 | //获取分页Sql语句 67 | String pageSql = this.getPageSql(myPage, sql); 68 | //利用反射设置当前BoundSql对应的sql属性为我们建立好的分页Sql语句 69 | ReflectUtil.setFieldValue(boundSql, "sql", pageSql); 70 | } 71 | return invocation.proceed(); 72 | } 73 | 74 | /** 75 | * 根据page对象获取对应的分页查询Sql语句,这里只做了两种数据库类型,Mysql和Oracle 76 | * 其它的数据库都 没有进行分页 77 | * 78 | * @param page 分页对象 79 | * @param sql 原sql语句 80 | * @return 81 | */ 82 | private String getPageSql(MyPage page, String sql) { 83 | StringBuffer sqlBuffer = new StringBuffer(sql); 84 | if ("mysql".equalsIgnoreCase(databaseType)) { 85 | return getMysqlPageSql(page, sqlBuffer); 86 | } else if ("oracle".equalsIgnoreCase(databaseType)) { 87 | return getOraclePageSql(page, sqlBuffer); 88 | } 89 | return sqlBuffer.toString(); 90 | } 91 | 92 | /** 93 | * 获取Mysql数据库的分页查询语句 94 | * @param page 分页对象 95 | * @param sqlBuffer 包含原sql语句的StringBuffer对象 96 | * @return Mysql数据库分页语句 97 | */ 98 | private String getMysqlPageSql(MyPage page, StringBuffer sqlBuffer) { 99 | //计算第一条记录的位置,Mysql中记录的位置是从0开始的。 100 | int offset = (page.getPageNo() - 1) * page.getPageSize(); 101 | sqlBuffer.append(" limit ").append(offset).append(",").append(page.getPageSize()); 102 | return sqlBuffer.toString(); 103 | } 104 | 105 | /** 106 | * 获取Oracle数据库的分页查询语句 107 | * @param page 分页对象 108 | * @param sqlBuffer 包含原sql语句的StringBuffer对象 109 | * @return Oracle数据库的分页查询语句 110 | */ 111 | private String getOraclePageSql(MyPage page, StringBuffer sqlBuffer) { 112 | //计算第一条记录的位置,Oracle分页是通过rownum进行的,而rownum是从1开始的 113 | int offset = (page.getPageNo() - 1) * page.getPageSize() + 1; 114 | sqlBuffer.insert(0, "select u.*, rownum r from (").append(") u where rownum < ").append(offset + page.getPageSize()); 115 | sqlBuffer.insert(0, "select * from (").append(") where r >= ").append(offset); 116 | //上面的Sql语句拼接之后大概是这个样子: 117 | //select * from (select u.*, rownum r from (select * from t_user) u where rownum < 31) where r >= 16 118 | return sqlBuffer.toString(); 119 | } 120 | 121 | /** 122 | * 给当前的参数对象page设置总记录数 123 | * 124 | * @param page Mapper映射语句对应的参数对象 125 | * @param mappedStatement Mapper映射语句 126 | * @param connection 当前的数据库连接 127 | */ 128 | private void setTotalRecord(MyPage page, 129 | MappedStatement mappedStatement, Connection connection) { 130 | //获取对应的BoundSql,这个BoundSql其实跟我们利用StatementHandler获取到的BoundSql是同一个对象。 131 | //delegate里面的boundSql也是通过mappedStatement.getBoundSql(paramObj)方法获取到的。 132 | BoundSql boundSql = mappedStatement.getBoundSql(page); 133 | //获取到我们自己写在Mapper映射语句中对应的Sql语句 134 | String sql = boundSql.getSql(); 135 | //通过查询Sql语句获取到对应的计算总记录数的sql语句 136 | String countSql = this.getCountSql(sql); 137 | //通过BoundSql获取对应的参数映射 138 | List parameterMappings = boundSql.getParameterMappings(); 139 | //利用Configuration、查询记录数的Sql语句countSql、参数映射关系parameterMappings和参数对象page建立查询记录数对应的BoundSql对象。 140 | BoundSql countBoundSql = new BoundSql(mappedStatement.getConfiguration(), countSql, parameterMappings, page); 141 | //通过mappedStatement、参数对象page和BoundSql对象countBoundSql建立一个用于设定参数的ParameterHandler对象 142 | ParameterHandler parameterHandler = new DefaultParameterHandler(mappedStatement, page, countBoundSql); 143 | //通过connection建立一个countSql对应的PreparedStatement对象。 144 | PreparedStatement pstmt = null; 145 | ResultSet rs = null; 146 | try { 147 | pstmt = connection.prepareStatement(countSql); 148 | //通过parameterHandler给PreparedStatement对象设置参数 149 | parameterHandler.setParameters(pstmt); 150 | //之后就是执行获取总记录数的Sql语句和获取结果了。 151 | rs = pstmt.executeQuery(); 152 | if (rs.next()) { 153 | int totalRecord = rs.getInt(1); 154 | //给当前的参数page对象设置总记录数 155 | page.setTotalRecord(totalRecord); 156 | } 157 | } catch (SQLException e) { 158 | e.printStackTrace(); 159 | } finally { 160 | try { 161 | if (rs != null) 162 | rs.close(); 163 | if (pstmt != null) 164 | pstmt.close(); 165 | } catch (SQLException e) { 166 | e.printStackTrace(); 167 | } 168 | } 169 | } 170 | 171 | /** 172 | * 根据原Sql语句获取对应的查询总记录数的Sql语句 173 | * @param sql 174 | * @return 175 | */ 176 | private String getCountSql(String sql) { 177 | 178 | return "select count(1) from (" + sql + ") b"; 179 | } 180 | 181 | @Override 182 | public Object plugin(Object target) { 183 | if (target instanceof StatementHandler) { 184 | return Plugin.wrap(target, this); 185 | } 186 | return target; 187 | } 188 | 189 | @Override 190 | public void setProperties(Properties properties) { 191 | this.databaseType = properties.getProperty("databaseType"); 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /mybatis-core/src/main/java/com/github/core/plugin/PerformanceInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.github.core.plugin; 2 | 3 | import org.apache.ibatis.cache.CacheKey; 4 | import org.apache.ibatis.executor.Executor; 5 | import org.apache.ibatis.mapping.BoundSql; 6 | import org.apache.ibatis.mapping.MappedStatement; 7 | import org.apache.ibatis.mapping.ParameterMapping; 8 | import org.apache.ibatis.mapping.ParameterMode; 9 | import org.apache.ibatis.plugin.*; 10 | import org.apache.ibatis.reflection.MetaObject; 11 | import org.apache.ibatis.session.Configuration; 12 | import org.apache.ibatis.session.ResultHandler; 13 | import org.apache.ibatis.session.RowBounds; 14 | import org.apache.ibatis.type.TypeHandlerRegistry; 15 | import org.slf4j.Logger; 16 | import org.slf4j.LoggerFactory; 17 | 18 | import java.text.DateFormat; 19 | import java.text.SimpleDateFormat; 20 | import java.util.Date; 21 | import java.util.List; 22 | import java.util.Properties; 23 | 24 | /** 25 | * MyBatis 性能拦截器,用于输出每条 SQL 语句及其执行时间 26 | * 27 | * User: 吴海旭 28 | * Date: 2017-06-18 29 | * Time: 下午7:41 30 | */ 31 | @Intercepts({ 32 | @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}), 33 | @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}) 34 | }) 35 | public class PerformanceInterceptor implements Interceptor { 36 | 37 | private Logger logger = LoggerFactory.getLogger(PerformanceInterceptor.class); 38 | private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 39 | 40 | @Override 41 | public Object intercept(Invocation invocation) throws Throwable { 42 | MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0]; 43 | String statementId = mappedStatement.getId(); 44 | Configuration configuration = mappedStatement.getConfiguration(); 45 | Object parameterObject = invocation.getArgs()[1]; 46 | BoundSql boundSql = mappedStatement.getBoundSql(parameterObject); 47 | String sql = getSql(boundSql, parameterObject, configuration); 48 | 49 | long start = System.currentTimeMillis(); 50 | 51 | Object result = invocation.proceed(); 52 | 53 | long end = System.currentTimeMillis(); 54 | long timing = end - start; 55 | 56 | logger.info("耗时:" + timing + " ms" + " - id:" + statementId + " - Sql:" + sql); 57 | return result; 58 | } 59 | 60 | @Override 61 | public Object plugin(Object target) { 62 | if (target instanceof Executor) { 63 | return Plugin.wrap(target, this); 64 | } 65 | return target; 66 | } 67 | 68 | @Override 69 | public void setProperties(Properties properties) { 70 | 71 | } 72 | 73 | /** 74 | * 获取待执行的sql语句 75 | * @param boundSql 76 | * @param parameterObject 参数对象,如果是多参数就是一个Map,对应着propertyName value 77 | * @param configuration 78 | * @return 79 | */ 80 | private String getSql(BoundSql boundSql, Object parameterObject, Configuration configuration) { 81 | String sql = boundSql.getSql().replaceAll("[\\s]+", " "); 82 | List parameterMappings = boundSql.getParameterMappings(); 83 | TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry(); 84 | if (parameterMappings != null) { 85 | for (int i = 0; i < parameterMappings.size(); i++) { 86 | ParameterMapping parameterMapping = parameterMappings.get(i); 87 | if (parameterMapping.getMode() != ParameterMode.OUT) { 88 | Object value; 89 | String propertyName = parameterMapping.getProperty(); 90 | if (boundSql.hasAdditionalParameter(propertyName)) { 91 | value = boundSql.getAdditionalParameter(propertyName); 92 | } else if (parameterObject == null) { 93 | value = null; 94 | } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) { 95 | // 单个参数,并且类型是typeHandlerRegistry已经存在的 96 | value = parameterObject; 97 | } else { 98 | // 多参数 99 | MetaObject metaObject = configuration.newMetaObject(parameterObject); 100 | value = metaObject.getValue(propertyName); 101 | } 102 | // 把?替换成值 103 | sql = replacePlaceholder(sql, value); 104 | } 105 | } 106 | } 107 | return sql; 108 | } 109 | 110 | private String replacePlaceholder(String sql, Object propertyValue) { 111 | String result; 112 | if (propertyValue != null) { 113 | if (propertyValue instanceof String) { 114 | result = "'" + propertyValue + "'"; 115 | } else if (propertyValue instanceof Date) { 116 | result = "'" + DATE_FORMAT.format(propertyValue) + "'"; 117 | } else { 118 | result = propertyValue.toString(); 119 | } 120 | } else { 121 | result = "null"; 122 | } 123 | return sql.replaceFirst("\\?", result); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /mybatis-core/src/main/java/com/github/core/util/MyBatisConfigHelper.java: -------------------------------------------------------------------------------- 1 | package com.github.core.util; 2 | 3 | import org.apache.ibatis.io.Resources; 4 | import org.apache.ibatis.session.ExecutorType; 5 | import org.apache.ibatis.session.SqlSession; 6 | import org.apache.ibatis.session.SqlSessionFactory; 7 | import org.apache.ibatis.session.SqlSessionFactoryBuilder; 8 | 9 | import java.io.IOException; 10 | import java.io.InputStream; 11 | 12 | /** 13 | * User: 吴海旭 14 | * Date: 2017-06-24 15 | * Time: 下午1:18 16 | */ 17 | public class MyBatisConfigHelper { 18 | 19 | private static SqlSessionFactory sqlSessionFactory; 20 | 21 | static { 22 | String resource = "mybatis-config.xml"; 23 | InputStream in = null; 24 | try { 25 | in = Resources.getResourceAsStream(resource); 26 | } catch (IOException e) { 27 | e.printStackTrace(); 28 | } 29 | sqlSessionFactory = new SqlSessionFactoryBuilder().build(in); 30 | } 31 | 32 | public static SqlSessionFactory getSqlSessionFactory() { 33 | return sqlSessionFactory; 34 | } 35 | 36 | public static SqlSession getSqlSession() { 37 | return sqlSessionFactory.openSession(); 38 | } 39 | 40 | public static SqlSession getSqlSession(boolean autoCommit) { 41 | return sqlSessionFactory.openSession(autoCommit); 42 | } 43 | 44 | public static SqlSession getSqlSession(ExecutorType executorType) { 45 | return sqlSessionFactory.openSession(executorType); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /mybatis-core/src/main/resources/mybatis-config.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /mybatis-generator/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | mybatis 5 | com.github 6 | 1.0-SNAPSHOT 7 | 8 | 4.0.0 9 | 10 | mybatis-generator 11 | jar 12 | 13 | mybatis-generator 14 | http://maven.apache.org 15 | 16 | 17 | 18 | com.github 19 | mybatis-base 20 | 1.0-SNAPSHOT 21 | 22 | 23 | org.mybatis.generator 24 | mybatis-generator-core 25 | 26 | 27 | postgresql 28 | postgresql 29 | 9.1-901-1.jdbc4 30 | 31 | 32 | 33 | 34 | 6.0.6 35 | 36 | 37 | 38 | 39 | 40 | src/main/resources/ 41 | true 42 | 43 | **/*.properties 44 | 45 | 46 | 47 | src/main/resources/ 48 | true 49 | 50 | **/*.xml 51 | 52 | 53 | 54 | 55 | 56 | org.mybatis.generator 57 | mybatis-generator-maven-plugin 58 | 1.3.2 59 | 60 | ${basedir}/src/main/resources/generatorConfigByMaven.xml 61 | true 62 | true 63 | 64 | 65 | 66 | mysql 67 | mysql-connector-java 68 | ${mysql.version} 69 | 70 | 74 | 75 | com.github 76 | mybatis-generator 77 | 1.0-SNAPSHOT 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | dev 87 | 88 | true 89 | 90 | 91 | 92 | com.mysql.cj.jdbc.Driver 93 | jdbc:mysql://localhost/mybatis?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC&nullNamePatternMatchesAll=true 94 | root 95 | 123456 96 | 97 | 98 | 99 | ${basedir}/src/main/java 100 | com.github.generator.mapper 101 | com.github.generator 102 | 103 | ${basedir}/src/main/resources 104 | mapper 105 | 106 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /mybatis-generator/src/main/java/com/github/generator/GeneratorPostgresTest.java: -------------------------------------------------------------------------------- 1 | package com.github.generator; 2 | 3 | import org.apache.ibatis.io.Resources; 4 | import org.mybatis.generator.api.MyBatisGenerator; 5 | import org.mybatis.generator.api.ProgressCallback; 6 | import org.mybatis.generator.api.VerboseProgressCallback; 7 | import org.mybatis.generator.config.Configuration; 8 | import org.mybatis.generator.config.xml.ConfigurationParser; 9 | import org.mybatis.generator.exception.InvalidConfigurationException; 10 | import org.mybatis.generator.exception.XMLParserException; 11 | import org.mybatis.generator.internal.DefaultShellCallback; 12 | 13 | import java.io.IOException; 14 | import java.io.InputStream; 15 | import java.sql.SQLException; 16 | import java.util.ArrayList; 17 | import java.util.List; 18 | 19 | /** 20 | * User: 吴海旭 21 | * Date: 2017-06-24 22 | * Time: 下午7:05 23 | */ 24 | public class GeneratorPostgresTest { 25 | 26 | public static void main(String[] args) throws IOException, XMLParserException, InvalidConfigurationException, SQLException, InterruptedException { 27 | List warnings = new ArrayList(); 28 | boolean overwrite = true; 29 | InputStream inputStream = Resources.getResourceAsStream("generatorPostgresConfig.xml"); 30 | ConfigurationParser cp = new ConfigurationParser(warnings); 31 | Configuration config = cp.parseConfiguration(inputStream); 32 | DefaultShellCallback callback = new DefaultShellCallback(overwrite); 33 | MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings); 34 | ProgressCallback progressCallback = new VerboseProgressCallback(); 35 | // myBatisGenerator.generate(null); 36 | myBatisGenerator.generate(progressCallback); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /mybatis-generator/src/main/java/com/github/generator/GeneratorTest.java: -------------------------------------------------------------------------------- 1 | package com.github.generator; 2 | 3 | import org.apache.ibatis.io.Resources; 4 | import org.mybatis.generator.api.MyBatisGenerator; 5 | import org.mybatis.generator.api.ProgressCallback; 6 | import org.mybatis.generator.api.VerboseProgressCallback; 7 | import org.mybatis.generator.config.Configuration; 8 | import org.mybatis.generator.config.xml.ConfigurationParser; 9 | import org.mybatis.generator.exception.InvalidConfigurationException; 10 | import org.mybatis.generator.exception.XMLParserException; 11 | import org.mybatis.generator.internal.DefaultShellCallback; 12 | 13 | import java.io.File; 14 | import java.io.IOException; 15 | import java.io.InputStream; 16 | import java.sql.SQLException; 17 | import java.util.ArrayList; 18 | import java.util.List; 19 | 20 | /** 21 | * User: 吴海旭 22 | * Date: 2017-06-24 23 | * Time: 下午7:05 24 | */ 25 | public class GeneratorTest { 26 | 27 | public static void main(String[] args) throws IOException, XMLParserException, InvalidConfigurationException, SQLException, InterruptedException { 28 | List warnings = new ArrayList(); 29 | boolean overwrite = true; 30 | InputStream inputStream = Resources.getResourceAsStream("generatorConfig.xml"); 31 | ConfigurationParser cp = new ConfigurationParser(warnings); 32 | Configuration config = cp.parseConfiguration(inputStream); 33 | DefaultShellCallback callback = new DefaultShellCallback(overwrite); 34 | MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings); 35 | ProgressCallback progressCallback = new VerboseProgressCallback(); 36 | // myBatisGenerator.generate(null); 37 | myBatisGenerator.generate(progressCallback); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /mybatis-generator/src/main/resources/generatorConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 38 | 39 | 47 | 48 | 49 |
50 | 51 | 52 |
53 | 54 | 55 |
56 | 57 | 58 |
59 | 60 | 61 |
62 | 63 | 64 |
65 | 66 | 67 |
68 | 69 | 70 |
71 | 72 | 73 |
74 | 75 | 76 |
77 | 78 | 79 |
80 |
81 |
-------------------------------------------------------------------------------- /mybatis-generator/src/main/resources/generatorConfigByMaven.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 35 | 36 | 37 | 38 |
39 | 40 | 41 |
42 | 43 | 44 |
45 |
46 |
-------------------------------------------------------------------------------- /mybatis-generator/src/main/resources/generatorPostgresConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 37 | 38 | 46 | 47 | 48 |
49 | 50 | 51 |
52 | 53 | 54 |
55 | 56 | 57 |
58 | 59 | 60 |
61 | 62 | 63 |
64 | 65 | 66 |
67 |
68 |
-------------------------------------------------------------------------------- /mybatis-mapper/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | mybatis 5 | com.github 6 | 1.0-SNAPSHOT 7 | 8 | 4.0.0 9 | 10 | mybatis-mapper 11 | jar 12 | 13 | mybatis-mapper 14 | http://maven.apache.org 15 | 16 | 17 | 18 | com.github 19 | mybatis-base 20 | 1.0-SNAPSHOT 21 | 22 | 23 | tk.mybatis 24 | mapper 25 | 26 | 27 | javax.persistence 28 | persistence-api 29 | 30 | 31 | 32 | 33 | 34 | 35 | ${basedir}/src/main/java 36 | com.github.mapper.mapper 37 | com.github.mapper.model 38 | 39 | ${basedir}/src/main/resources 40 | mapper 41 | 42 | 6.0.6 43 | 44 | 45 | 46 | 47 | 48 | org.mybatis.generator 49 | mybatis-generator-maven-plugin 50 | 1.3.2 51 | 52 | ${basedir}/src/main/resources/generatorConfigByMaven.xml 53 | true 54 | true 55 | 56 | 57 | 58 | mysql 59 | mysql-connector-java 60 | ${mysql.version} 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /mybatis-mapper/src/main/java/com/github/mapper/mapper/CommonMapper.java: -------------------------------------------------------------------------------- 1 | package com.github.mapper.mapper; 2 | 3 | import tk.mybatis.mapper.common.IdsMapper; 4 | import tk.mybatis.mapper.common.Mapper; 5 | import tk.mybatis.mapper.common.MySqlMapper; 6 | 7 | /** 8 | * User: 吴海旭 9 | * Date: 2017-06-25 10 | * Time: 下午3:35 11 | */ 12 | public interface CommonMapper extends Mapper, IdsMapper, InsertLogIdMapper { 13 | } 14 | -------------------------------------------------------------------------------- /mybatis-mapper/src/main/java/com/github/mapper/mapper/InsertLogIdMapper.java: -------------------------------------------------------------------------------- 1 | package com.github.mapper.mapper; 2 | 3 | import org.apache.ibatis.annotations.InsertProvider; 4 | import org.apache.ibatis.annotations.Options; 5 | import tk.mybatis.mapper.provider.SpecialProvider; 6 | 7 | /** 8 | * User: 吴海旭 9 | * Date: 2017-06-25 10 | * Time: 下午3:47 11 | * 主键不是id,自定义mapper 12 | */ 13 | public interface InsertLogIdMapper { 14 | 15 | @Options(useGeneratedKeys = true, keyProperty = "logid") 16 | @InsertProvider(type = SpecialProvider.class, method = "dynamicSQL") 17 | int insertUseGeneratedKeys(T record); 18 | } 19 | -------------------------------------------------------------------------------- /mybatis-mapper/src/main/java/com/github/mapper/mapper/UserLoginMapper.java: -------------------------------------------------------------------------------- 1 | package com.github.mapper.mapper; 2 | 3 | import com.github.mapper.model.UserLogin; 4 | 5 | import tk.mybatis.mapper.common.Mapper; 6 | import tk.mybatis.mapper.common.MySqlMapper; 7 | 8 | public interface UserLoginMapper extends CommonMapper { 9 | } -------------------------------------------------------------------------------- /mybatis-mapper/src/main/java/com/github/mapper/model/UserLogin.java: -------------------------------------------------------------------------------- 1 | package com.github.mapper.model; 2 | 3 | import tk.mybatis.mapper.entity.IDynamicTableName; 4 | 5 | import javax.persistence.*; 6 | import java.io.Serializable; 7 | import java.util.Date; 8 | 9 | @Table(name = "user_login") 10 | public class UserLogin implements Serializable, IDynamicTableName { 11 | private static final long serialVersionUID = -445441931554119345L; 12 | 13 | @Id 14 | @GeneratedValue(generator = "JDBC") 15 | // @OrderBy("desc") 16 | private Long logid; 17 | 18 | private String username; 19 | 20 | private Date logindate; 21 | 22 | private String loginip; 23 | 24 | @Transient 25 | private String dynamicTableName; 26 | 27 | public Long getLogid() { 28 | return logid; 29 | } 30 | 31 | public void setLogid(Long logid) { 32 | this.logid = logid; 33 | } 34 | 35 | public String getUsername() { 36 | return username; 37 | } 38 | 39 | public void setUsername(String username) { 40 | this.username = username == null ? null : username.trim(); 41 | } 42 | 43 | public Date getLogindate() { 44 | return logindate; 45 | } 46 | 47 | public void setLogindate(Date logindate) { 48 | this.logindate = logindate; 49 | } 50 | 51 | public String getLoginip() { 52 | return loginip; 53 | } 54 | 55 | public void setLoginip(String loginip) { 56 | this.loginip = loginip == null ? null : loginip.trim(); 57 | } 58 | 59 | @Override 60 | public String toString() { 61 | return "UserLogin{" + 62 | "logid=" + logid + 63 | ", username='" + username + '\'' + 64 | ", logindate=" + logindate + 65 | ", loginip='" + loginip + '\'' + 66 | '}'; 67 | } 68 | 69 | @Override 70 | public String getDynamicTableName() { 71 | return dynamicTableName; 72 | } 73 | 74 | public void setDynamicTableName(String dynamicTableName) { 75 | this.dynamicTableName = dynamicTableName; 76 | } 77 | } -------------------------------------------------------------------------------- /mybatis-mapper/src/main/java/com/github/mapper/plugin/PerformanceInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.github.mapper.plugin; 2 | 3 | import org.apache.ibatis.executor.Executor; 4 | import org.apache.ibatis.mapping.BoundSql; 5 | import org.apache.ibatis.mapping.MappedStatement; 6 | import org.apache.ibatis.mapping.ParameterMapping; 7 | import org.apache.ibatis.mapping.ParameterMode; 8 | import org.apache.ibatis.plugin.*; 9 | import org.apache.ibatis.reflection.MetaObject; 10 | import org.apache.ibatis.session.Configuration; 11 | import org.apache.ibatis.session.ResultHandler; 12 | import org.apache.ibatis.session.RowBounds; 13 | import org.apache.ibatis.type.TypeHandlerRegistry; 14 | import org.slf4j.Logger; 15 | import org.slf4j.LoggerFactory; 16 | 17 | import java.text.DateFormat; 18 | import java.text.SimpleDateFormat; 19 | import java.util.Date; 20 | import java.util.List; 21 | import java.util.Properties; 22 | 23 | /** 24 | * MyBatis 性能拦截器,用于输出每条 SQL 语句及其执行时间 25 | * 26 | * User: 吴海旭 27 | * Date: 2017-06-18 28 | * Time: 下午7:41 29 | */ 30 | @Intercepts({ 31 | @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}), 32 | @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}) 33 | }) 34 | public class PerformanceInterceptor implements Interceptor { 35 | 36 | private Logger logger = LoggerFactory.getLogger(PerformanceInterceptor.class); 37 | private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 38 | 39 | @Override 40 | public Object intercept(Invocation invocation) throws Throwable { 41 | MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0]; 42 | String statementId = mappedStatement.getId(); 43 | Configuration configuration = mappedStatement.getConfiguration(); 44 | Object parameterObject = invocation.getArgs()[1]; 45 | BoundSql boundSql = mappedStatement.getBoundSql(parameterObject); 46 | String sql = getSql(boundSql, parameterObject, configuration); 47 | 48 | long start = System.currentTimeMillis(); 49 | 50 | Object result = invocation.proceed(); 51 | 52 | long end = System.currentTimeMillis(); 53 | long timing = end - start; 54 | 55 | logger.info("耗时:" + timing + " ms" + " - id:" + statementId + " - Sql:" + sql); 56 | return result; 57 | } 58 | 59 | @Override 60 | public Object plugin(Object target) { 61 | if (target instanceof Executor) { 62 | return Plugin.wrap(target, this); 63 | } 64 | return target; 65 | } 66 | 67 | @Override 68 | public void setProperties(Properties properties) { 69 | 70 | } 71 | 72 | /** 73 | * 获取待执行的sql语句 74 | * @param boundSql 75 | * @param parameterObject 参数对象,如果是多参数就是一个Map,对应着propertyName value 76 | * @param configuration 77 | * @return 78 | */ 79 | private String getSql(BoundSql boundSql, Object parameterObject, Configuration configuration) { 80 | String sql = boundSql.getSql().replaceAll("[\\s]+", " "); 81 | List parameterMappings = boundSql.getParameterMappings(); 82 | TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry(); 83 | if (parameterMappings != null) { 84 | for (int i = 0; i < parameterMappings.size(); i++) { 85 | ParameterMapping parameterMapping = parameterMappings.get(i); 86 | if (parameterMapping.getMode() != ParameterMode.OUT) { 87 | Object value; 88 | String propertyName = parameterMapping.getProperty(); 89 | if (boundSql.hasAdditionalParameter(propertyName)) { 90 | value = boundSql.getAdditionalParameter(propertyName); 91 | } else if (parameterObject == null) { 92 | value = null; 93 | } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) { 94 | // 单个参数,并且类型是typeHandlerRegistry已经存在的 95 | value = parameterObject; 96 | } else { 97 | // 多参数 98 | MetaObject metaObject = configuration.newMetaObject(parameterObject); 99 | value = metaObject.getValue(propertyName); 100 | } 101 | // 把?替换成值 102 | sql = replacePlaceholder(sql, value); 103 | } 104 | } 105 | } 106 | return sql; 107 | } 108 | 109 | private String replacePlaceholder(String sql, Object propertyValue) { 110 | String result; 111 | if (propertyValue != null) { 112 | if (propertyValue instanceof String) { 113 | result = "'" + propertyValue + "'"; 114 | } else if (propertyValue instanceof Date) { 115 | result = "'" + DATE_FORMAT.format(propertyValue) + "'"; 116 | } else { 117 | result = propertyValue.toString(); 118 | } 119 | } else { 120 | result = "null"; 121 | } 122 | return sql.replaceFirst("\\?", result); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /mybatis-mapper/src/main/java/com/github/mapper/test/CommonMapperTest.java: -------------------------------------------------------------------------------- 1 | package com.github.mapper.test; 2 | 3 | import com.github.base.util.PrintUtil; 4 | import com.github.mapper.mapper.UserLoginMapper; 5 | import com.github.mapper.model.UserLogin; 6 | import com.github.mapper.util.CommonMapperHelper; 7 | import org.apache.ibatis.session.SqlSession; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | import tk.mybatis.mapper.entity.Example; 11 | 12 | import java.util.Date; 13 | import java.util.List; 14 | 15 | /** 16 | * User: 吴海旭 17 | * Date: 2017-06-25 18 | * Time: 下午1:43 19 | */ 20 | public class CommonMapperTest { 21 | 22 | private static Logger logger = LoggerFactory.getLogger(CommonMapperTest.class); 23 | 24 | private void testMapper1() { 25 | SqlSession sqlSession = CommonMapperHelper.getSqlSession(); 26 | UserLoginMapper mapper = sqlSession.getMapper(UserLoginMapper.class); 27 | UserLogin userLogin = new UserLogin(); 28 | userLogin.setUsername("test2"); 29 | // 设置动态表名 30 | userLogin.setDynamicTableName("user_login2"); 31 | List select = mapper.select(userLogin); 32 | PrintUtil.printList(select, logger); 33 | } 34 | 35 | private void testMapper2() { 36 | SqlSession sqlSession = CommonMapperHelper.getSqlSession(); 37 | UserLoginMapper mapper = sqlSession.getMapper(UserLoginMapper.class); 38 | Example example = new Example(UserLogin.class); 39 | example.createCriteria().andEqualTo("username", "test1"); 40 | example.setTableName("user_login2"); 41 | List userLogins = mapper.selectByExample(example); 42 | PrintUtil.printList(userLogins, logger); 43 | } 44 | 45 | private void testMapper3() { 46 | SqlSession sqlSession = CommonMapperHelper.getSqlSession(true); 47 | UserLoginMapper mapper = sqlSession.getMapper(UserLoginMapper.class); 48 | UserLogin userLogin = new UserLogin(); 49 | userLogin.setUsername("benjamin"); 50 | userLogin.setLogindate(new Date()); 51 | userLogin.setLoginip("192.168.1.1"); 52 | int i = mapper.insertUseGeneratedKeys(userLogin); 53 | logger.info("i=" + i + ", id=" + userLogin.getLogid()); 54 | } 55 | 56 | private void testMapper4() { 57 | SqlSession sqlSession = CommonMapperHelper.getSqlSession(true); 58 | UserLoginMapper mapper = sqlSession.getMapper(UserLoginMapper.class); 59 | List userLogins = mapper.selectByIds("2,3,4,5"); 60 | PrintUtil.printList(userLogins, logger); 61 | } 62 | 63 | private void testMapper5() { 64 | SqlSession sqlSession = CommonMapperHelper.getSqlSession(true); 65 | UserLoginMapper mapper = sqlSession.getMapper(UserLoginMapper.class); 66 | int i = mapper.deleteByPrimaryKey(1L); 67 | logger.info("i=" + i); 68 | } 69 | 70 | public static void main(String[] args) { 71 | CommonMapperTest test = new CommonMapperTest(); 72 | // test.testMapper1(); 73 | // test.testMapper2(); 74 | test.testMapper3(); 75 | // test.testMapper4(); 76 | // test.testMapper5(); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /mybatis-mapper/src/main/java/com/github/mapper/util/CommonMapperHelper.java: -------------------------------------------------------------------------------- 1 | package com.github.mapper.util; 2 | 3 | import com.github.mapper.mapper.InsertLogIdMapper; 4 | import org.apache.ibatis.io.Resources; 5 | import org.apache.ibatis.session.SqlSession; 6 | import org.apache.ibatis.session.SqlSessionFactory; 7 | import org.apache.ibatis.session.SqlSessionFactoryBuilder; 8 | import tk.mybatis.mapper.common.IdsMapper; 9 | import tk.mybatis.mapper.common.Mapper; 10 | import tk.mybatis.mapper.common.MySqlMapper; 11 | import tk.mybatis.mapper.common.special.InsertUseGeneratedKeysMapper; 12 | import tk.mybatis.mapper.entity.Config; 13 | import tk.mybatis.mapper.mapperhelper.MapperHelper; 14 | 15 | import java.io.IOException; 16 | import java.io.InputStream; 17 | 18 | /** 19 | * User: 吴海旭 20 | * Date: 2017-06-25 21 | * Time: 下午1:43 22 | */ 23 | public class CommonMapperHelper { 24 | 25 | private static SqlSessionFactory sqlSessionFactory; 26 | 27 | static { 28 | String resource = "mybatis-config.xml"; 29 | InputStream in = null; 30 | try { 31 | in = Resources.getResourceAsStream(resource); 32 | } catch (IOException e) { 33 | e.printStackTrace(); 34 | } 35 | sqlSessionFactory = new SqlSessionFactoryBuilder().build(in); 36 | 37 | MapperHelper mapperHelper = new MapperHelper(); 38 | Config config = new Config(); 39 | config.setEnableMethodAnnotation(true); 40 | mapperHelper.setConfig(config); 41 | 42 | mapperHelper.registerMapper(Mapper.class); 43 | // mapperHelper.registerMapper(MySqlMapper.class); 44 | mapperHelper.registerMapper(IdsMapper.class); 45 | mapperHelper.registerMapper(InsertLogIdMapper.class); 46 | 47 | mapperHelper.processConfiguration(getSqlSession().getConfiguration()); 48 | } 49 | 50 | public static SqlSessionFactory getSqlSessionFactory() { 51 | return sqlSessionFactory; 52 | } 53 | 54 | public static SqlSession getSqlSession() { 55 | return sqlSessionFactory.openSession(); 56 | } 57 | 58 | public static SqlSession getSqlSession(boolean autoCommit) { 59 | return sqlSessionFactory.openSession(autoCommit); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /mybatis-mapper/src/main/resources/dbConfig.properties: -------------------------------------------------------------------------------- 1 | mysql.driver=com.mysql.cj.jdbc.Driver 2 | mysql.url=jdbc:mysql://localhost/mybatis?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC 3 | mysql.userName=root 4 | mysql.password=123456 5 | 6 | mysql.initialSize=2 7 | mysql.maxActive=20 8 | mysql.maxIdle=20 9 | mysql.minIdle=0 10 | mysql.poolPreparedStatements=true 11 | mysql.defaultAutoCommit=false -------------------------------------------------------------------------------- /mybatis-mapper/src/main/resources/generatorConfigByMaven.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 39 | 40 | 48 | 49 | 50 |
51 |
52 |
-------------------------------------------------------------------------------- /mybatis-mapper/src/main/resources/mybatis-config.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /mybatis-order/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | mybatis 5 | com.github 6 | 1.0-SNAPSHOT 7 | 8 | 4.0.0 9 | 10 | mybatis-order 11 | jar 12 | 13 | mybatis-order 14 | http://maven.apache.org 15 | 16 | 17 | 18 | com.github 19 | mybatis-base 20 | 1.0-SNAPSHOT 21 | 22 | 23 | tk.mybatis 24 | orderby-helper 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /mybatis-order/src/main/java/com/github/order/OrderByTest.java: -------------------------------------------------------------------------------- 1 | package com.github.order; 2 | 3 | import com.github.base.bean.User; 4 | import com.github.base.mapper.UserMapper; 5 | import com.github.base.util.PrintUtil; 6 | import com.github.order.util.OrderConfigHelper; 7 | import org.apache.ibatis.session.SqlSession; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | import tk.mybatis.orderbyhelper.OrderByHelper; 11 | 12 | import java.util.List; 13 | 14 | /** 15 | * User: 吴海旭 16 | * Date: 2017-06-24 17 | * Time: 下午5:22 18 | */ 19 | public class OrderByTest { 20 | 21 | private Logger logger = LoggerFactory.getLogger(OrderByTest.class); 22 | 23 | private void selectUserOrderByInterceptor() { 24 | SqlSession sqlSession = OrderConfigHelper.getSqlSession(true); 25 | UserMapper mapper = sqlSession.getMapper(UserMapper.class); 26 | 27 | // 按id desc排序输出 28 | OrderByHelper.orderBy("id desc"); 29 | List allUsers = mapper.getAllUsers(); 30 | PrintUtil.printList(allUsers, logger); 31 | } 32 | 33 | public static void main(String[] args) { 34 | OrderByTest test = new OrderByTest(); 35 | test.selectUserOrderByInterceptor(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /mybatis-order/src/main/java/com/github/order/util/OrderConfigHelper.java: -------------------------------------------------------------------------------- 1 | package com.github.order.util; 2 | 3 | import org.apache.ibatis.io.Resources; 4 | import org.apache.ibatis.session.SqlSession; 5 | import org.apache.ibatis.session.SqlSessionFactory; 6 | import org.apache.ibatis.session.SqlSessionFactoryBuilder; 7 | 8 | import java.io.IOException; 9 | import java.io.InputStream; 10 | 11 | /** 12 | * User: 吴海旭 13 | * Date: 2017-06-24 14 | * Time: 下午5:20 15 | */ 16 | public class OrderConfigHelper { 17 | 18 | private static SqlSessionFactory sqlSessionFactory; 19 | 20 | static { 21 | String resource = "order-config.xml"; 22 | InputStream in = null; 23 | try { 24 | in = Resources.getResourceAsStream(resource); 25 | } catch (IOException e) { 26 | e.printStackTrace(); 27 | } 28 | sqlSessionFactory = new SqlSessionFactoryBuilder().build(in); 29 | } 30 | 31 | public static SqlSessionFactory getSqlSessionFactory() { 32 | return sqlSessionFactory; 33 | } 34 | 35 | public static SqlSession getSqlSession() { 36 | return sqlSessionFactory.openSession(); 37 | } 38 | 39 | public static SqlSession getSqlSession(boolean autoCommit) { 40 | return sqlSessionFactory.openSession(autoCommit); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /mybatis-order/src/main/resources/order-config.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /mybatis-page/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | mybatis 5 | com.github 6 | 1.0-SNAPSHOT 7 | 8 | 4.0.0 9 | 10 | mybatis-page 11 | jar 12 | 13 | mybatis-page 14 | http://maven.apache.org 15 | 16 | 17 | 18 | com.github 19 | mybatis-base 20 | 1.0-SNAPSHOT 21 | 22 | 23 | com.github.pagehelper 24 | pagehelper 25 | 5.0.2 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /mybatis-page/src/main/java/com/github/page/PageInterceptorTest.java: -------------------------------------------------------------------------------- 1 | package com.github.page; 2 | 3 | import com.github.base.bean.User; 4 | import com.github.base.mapper.UserMapper; 5 | import com.github.base.util.PrintUtil; 6 | import com.github.page.util.PageConfigHelper; 7 | import com.github.pagehelper.PageHelper; 8 | import com.github.pagehelper.PageRowBounds; 9 | import org.apache.ibatis.session.SqlSession; 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | 13 | import java.util.List; 14 | 15 | /** 16 | * User: 吴海旭 17 | * Date: 2017-06-24 18 | * Time: 下午5:04 19 | */ 20 | public class PageInterceptorTest { 21 | 22 | private Logger logger = LoggerFactory.getLogger(PageInterceptorTest.class); 23 | 24 | /** 25 | * 第一种:RowBounds方式调用 26 | */ 27 | private void selectUsePageInterceptor1() { 28 | SqlSession sqlSession = PageConfigHelper.getSqlSession(true); 29 | UserMapper mapper = sqlSession.getMapper(UserMapper.class); 30 | // 默认不查询count值 31 | // 需要查询配置page-config.xml rowBoundsWithCount 为true 32 | PageRowBounds pageRowBounds = new PageRowBounds(0, 6); 33 | List userListByRowBounds = mapper.getUserByRowBounds(pageRowBounds); 34 | logger.info("pageRowBounds count: " + pageRowBounds.getTotal()); 35 | PrintUtil.printList(userListByRowBounds, logger); 36 | } 37 | 38 | /** 39 | * 第二种:Mapper接口方式调用,推荐使用。 40 | */ 41 | private void selectUsePageInterceptor2() { 42 | SqlSession sqlSession = PageConfigHelper.getSqlSession(true); 43 | UserMapper mapper = sqlSession.getMapper(UserMapper.class); 44 | // 默认开启查询总数 45 | // com.github.pagehelper.Page page = PageHelper.startPage(1, 6); 46 | // 不开启查询总数 47 | // com.github.pagehelper.Page page = PageHelper.startPage(1, 6, false); 48 | // offset开始查询 49 | com.github.pagehelper.Page page = PageHelper.offsetPage(0, 6, false); 50 | mapper.getAllUsers(); 51 | 52 | logger.info("总数:" + page.getTotal()); 53 | PrintUtil.printList(page.getResult(), logger); 54 | } 55 | 56 | /** 57 | * 第三种:参数方式调用,不推荐使用,源码见 PageObjectUtil 这个类 58 | * 参数有以下几种: 59 | * pageNum 第几页 60 | * pageSize 每页页数 61 | * countSql 是否执行count sql 62 | * reasonable 分页合理化,当你传入的页数不对时会自动合理计算,默认false 63 | * pageSizeZero 当设置为true的时候,如果pagesize设置为0(或RowBounds的limit=0),就不执行分页,返回全部结果 64 | */ 65 | private void selectUsePageInterceptor3() { 66 | SqlSession sqlSession = PageConfigHelper.getSqlSession(true); 67 | UserMapper mapper = sqlSession.getMapper(UserMapper.class); 68 | // 不开启查询总数 69 | List userByPage = mapper.getUserByPageParam(0, 6, false); 70 | PrintUtil.printList(userByPage, logger); 71 | } 72 | 73 | /** 74 | * 第四种:使用ISelect接口方式 75 | */ 76 | private void selectUsePageInterceptor4() { 77 | SqlSession sqlSession = PageConfigHelper.getSqlSession(true); 78 | UserMapper mapper = sqlSession.getMapper(UserMapper.class); 79 | // 不开启查询总数 80 | com.github.pagehelper.Page page = PageHelper.startPage(0, 6).doSelectPage(() -> { 81 | mapper.getAllUsers(); 82 | }); 83 | logger.info("总数:" + page.getTotal()); 84 | PrintUtil.printList(page.getResult(), logger); 85 | 86 | // 计算总数 87 | long count = PageHelper.count(() -> { 88 | mapper.getAllUsers(); 89 | }); 90 | System.out.println("总数2:" + count); 91 | } 92 | 93 | public static void main(String[] args) { 94 | PageInterceptorTest test = new PageInterceptorTest(); 95 | test.selectUsePageInterceptor1(); 96 | // test.selectUsePageInterceptor2(); 97 | // test.selectUsePageInterceptor3(); 98 | // test.selectUsePageInterceptor4(); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /mybatis-page/src/main/java/com/github/page/plugin/PerformanceInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.github.page.plugin; 2 | 3 | import org.apache.ibatis.cache.CacheKey; 4 | import org.apache.ibatis.executor.Executor; 5 | import org.apache.ibatis.mapping.BoundSql; 6 | import org.apache.ibatis.mapping.MappedStatement; 7 | import org.apache.ibatis.mapping.ParameterMapping; 8 | import org.apache.ibatis.mapping.ParameterMode; 9 | import org.apache.ibatis.plugin.*; 10 | import org.apache.ibatis.reflection.MetaObject; 11 | import org.apache.ibatis.session.Configuration; 12 | import org.apache.ibatis.session.ResultHandler; 13 | import org.apache.ibatis.session.RowBounds; 14 | import org.apache.ibatis.type.TypeHandlerRegistry; 15 | 16 | import java.text.DateFormat; 17 | import java.text.SimpleDateFormat; 18 | import java.util.Date; 19 | import java.util.List; 20 | import java.util.Properties; 21 | 22 | /** 23 | * MyBatis 性能拦截器,用于输出每条 SQL 语句及其执行时间 24 | * 25 | * User: 吴海旭 26 | * Date: 2017-06-18 27 | * Time: 下午7:41 28 | */ 29 | @Intercepts({ 30 | @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}), 31 | @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}) 32 | }) 33 | public class PerformanceInterceptor implements Interceptor { 34 | 35 | private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 36 | 37 | @Override 38 | public Object intercept(Invocation invocation) throws Throwable { 39 | MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0]; 40 | String statementId = mappedStatement.getId(); 41 | Configuration configuration = mappedStatement.getConfiguration(); 42 | Object parameterObject = invocation.getArgs()[1]; 43 | BoundSql boundSql = null; 44 | 45 | if ("query".equals(invocation.getMethod().getName())) { 46 | // Fix bug @See:https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/Interceptor.md 47 | boundSql = (BoundSql) invocation.getArgs()[5]; 48 | } else { 49 | boundSql = mappedStatement.getBoundSql(parameterObject); 50 | } 51 | String sql = getSql(boundSql, parameterObject, configuration); 52 | 53 | long start = System.currentTimeMillis(); 54 | 55 | Object result = invocation.proceed(); 56 | 57 | long end = System.currentTimeMillis(); 58 | long timing = end - start; 59 | 60 | System.out.println("耗时:" + timing + " ms" + " - id:" + statementId + " - Sql:" + sql); 61 | return result; 62 | } 63 | 64 | @Override 65 | public Object plugin(Object target) { 66 | if (target instanceof Executor) { 67 | return Plugin.wrap(target, this); 68 | } 69 | return target; 70 | } 71 | 72 | @Override 73 | public void setProperties(Properties properties) { 74 | 75 | } 76 | 77 | /** 78 | * 获取待执行的sql语句 79 | * @param boundSql 80 | * @param parameterObject 参数对象,如果是多参数就是一个Map,对应着propertyName value 81 | * @param configuration 82 | * @return 83 | */ 84 | private String getSql(BoundSql boundSql, Object parameterObject, Configuration configuration) { 85 | String sql = boundSql.getSql().replaceAll("[\\s]+", " "); 86 | List parameterMappings = boundSql.getParameterMappings(); 87 | TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry(); 88 | if (parameterMappings != null) { 89 | for (int i = 0; i < parameterMappings.size(); i++) { 90 | ParameterMapping parameterMapping = parameterMappings.get(i); 91 | if (parameterMapping.getMode() != ParameterMode.OUT) { 92 | Object value; 93 | String propertyName = parameterMapping.getProperty(); 94 | if (boundSql.hasAdditionalParameter(propertyName)) { 95 | value = boundSql.getAdditionalParameter(propertyName); 96 | } else if (parameterObject == null) { 97 | value = null; 98 | } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) { 99 | // 单个参数,并且类型是typeHandlerRegistry已经存在的 100 | value = parameterObject; 101 | } else { 102 | // 多参数 103 | MetaObject metaObject = configuration.newMetaObject(parameterObject); 104 | value = metaObject.getValue(propertyName); 105 | } 106 | // 把?替换成值 107 | sql = replacePlaceholder(sql, value); 108 | } 109 | } 110 | } 111 | return sql; 112 | } 113 | 114 | private String replacePlaceholder(String sql, Object propertyValue) { 115 | String result; 116 | if (propertyValue != null) { 117 | if (propertyValue instanceof String) { 118 | result = "'" + propertyValue + "'"; 119 | } else if (propertyValue instanceof Date) { 120 | result = "'" + DATE_FORMAT.format(propertyValue) + "'"; 121 | } else { 122 | result = propertyValue.toString(); 123 | } 124 | } else { 125 | result = "null"; 126 | } 127 | return sql.replaceFirst("\\?", result); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /mybatis-page/src/main/java/com/github/page/util/PageConfigHelper.java: -------------------------------------------------------------------------------- 1 | package com.github.page.util; 2 | 3 | import org.apache.ibatis.io.Resources; 4 | import org.apache.ibatis.session.SqlSession; 5 | import org.apache.ibatis.session.SqlSessionFactory; 6 | import org.apache.ibatis.session.SqlSessionFactoryBuilder; 7 | 8 | import java.io.IOException; 9 | import java.io.InputStream; 10 | 11 | /** 12 | * User: 吴海旭 13 | * Date: 2017-06-24 14 | * Time: 下午5:09 15 | */ 16 | public class PageConfigHelper { 17 | 18 | private static SqlSessionFactory sqlSessionFactory; 19 | 20 | static { 21 | String resource = "page-config.xml"; 22 | InputStream in = null; 23 | try { 24 | in = Resources.getResourceAsStream(resource); 25 | } catch (IOException e) { 26 | e.printStackTrace(); 27 | } 28 | sqlSessionFactory = new SqlSessionFactoryBuilder().build(in); 29 | } 30 | 31 | public static SqlSessionFactory getSqlSessionFactory() { 32 | return sqlSessionFactory; 33 | } 34 | 35 | public static SqlSession getSqlSession() { 36 | return sqlSessionFactory.openSession(); 37 | } 38 | 39 | public static SqlSession getSqlSession(boolean autoCommit) { 40 | return sqlSessionFactory.openSession(autoCommit); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /mybatis-page/src/main/resources/page-config.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 29 | 30 | 31 | 32 | 33 | 43 | 44 | 45 | 51 | 52 | 53 | 58 | 59 | 60 | 65 | 66 | 67 | 72 | 73 | 74 | 78 | 79 | 80 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /mybatis-plugin/README.md: -------------------------------------------------------------------------------- 1 | # 一些实用的插件 2 | 3 | ## 1、AutoIncrementKeyPlugin插件使用 4 | 5 | 改变带有自增id的insert语句的执行行为, 由数据库执行后返回id的方式修改为在执行前设置id的值, 添加insert id列值的方式。 6 | 7 | 使用方法: 8 | 在mybatis配置文件中添加插件配置, 如下实例: 9 | 10 | ``` 11 | 12 | 13 | 14 | 15 | 18 | 19 | 21 | 22 | 23 | 24 | 25 | 26 | ``` 27 | 28 | ## 2、监控sql异常, 慢sql, 连接数报警插件使用 29 | 30 | 通过mybatis插件拦截Executor接口的query和update方法, 在执行时做异常捕获, 慢sql统计, 以及连接数阀值监控。 31 | 32 | 配置如下: 33 | 34 | ``` 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | ``` 45 | 46 | ## 3、主从配置插件 47 | 48 | 详细的看com/github/plugin/rw下的配置 -------------------------------------------------------------------------------- /mybatis-plugin/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | mybatis 5 | com.github 6 | 1.0-SNAPSHOT 7 | 8 | 4.0.0 9 | 10 | mybatis-plugin 11 | jar 12 | 13 | mybatis-plugin 14 | http://maven.apache.org 15 | 16 | 17 | UTF-8 18 | 19 | 20 | 21 | 22 | junit 23 | junit 24 | 25 | 26 | com.github 27 | mybatis-base 28 | 1.0-SNAPSHOT 29 | 30 | 31 | commons-dbcp 32 | commons-dbcp 33 | 34 | 35 | org.springframework 36 | spring-webmvc 37 | 38 | 39 | org.springframework 40 | spring-jdbc 41 | 42 | 43 | org.mybatis 44 | mybatis-spring 45 | 46 | 47 | org.aspectj 48 | aspectjrt 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /mybatis-plugin/src/main/java/com/github/plugin/PluginUtils.java: -------------------------------------------------------------------------------- 1 | package com.github.plugin; 2 | 3 | import org.apache.ibatis.executor.statement.StatementHandler; 4 | import org.apache.ibatis.reflection.MetaObject; 5 | import org.apache.ibatis.reflection.SystemMetaObject; 6 | 7 | /** 8 | * User: 吴海旭 9 | * Date: 2017-06-30 10 | * Time: 下午1:07 11 | */ 12 | public class PluginUtils { 13 | static class SqlIdHolder { 14 | final String sqlId; 15 | SqlIdHolder(String sqlId) { 16 | this.sqlId = sqlId; 17 | } 18 | } 19 | 20 | static ThreadLocal sqlIdHolderThreadLocal = new ThreadLocal<>(); 21 | 22 | public static void setSqlId(String sqlId) { 23 | sqlIdHolderThreadLocal.set(new SqlIdHolder(sqlId)); 24 | } 25 | 26 | public static String getSqlId() { 27 | return sqlIdHolderThreadLocal.get().sqlId; 28 | } 29 | 30 | public static void clearSqlId() { 31 | sqlIdHolderThreadLocal.remove(); 32 | } 33 | 34 | public static final String MAPPED_STATEMENT_KEY = "delegate.mappedStatement"; 35 | 36 | public static MetaObject getRealStatementHandler(StatementHandler handler) { 37 | MetaObject metaStatementHandler = SystemMetaObject.forObject(handler); 38 | // 分离代理对象链(由于目标类可能被多个拦截器拦截,从而形成多次代理,通过下面的两次循环 39 | // 可以分离出最原始的的目标类) 40 | while (metaStatementHandler.hasGetter("h")) { 41 | Object object = metaStatementHandler.getValue("h"); 42 | metaStatementHandler = SystemMetaObject.forObject(object); 43 | } 44 | // 分离最后一个代理对象的目标类 45 | while (metaStatementHandler.hasGetter("target")) { 46 | Object object = metaStatementHandler.getValue("target"); 47 | metaStatementHandler = SystemMetaObject.forObject(object); 48 | } 49 | return metaStatementHandler; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /mybatis-plugin/src/main/java/com/github/plugin/id/IDGen.java: -------------------------------------------------------------------------------- 1 | package com.github.plugin.id; 2 | 3 | /** 4 | * 5 | * ID生成器接口 6 | * 7 | * User: 吴海旭 8 | * Date: 2017-06-28 9 | * Time: 下午5:30 10 | */ 11 | public interface IDGen { 12 | 13 | /** 14 | * 根据传入的表名获得自增id 15 | * @param tableName 表名 16 | * @return long类型的自增id 17 | */ 18 | long newId(String tableName); 19 | } 20 | -------------------------------------------------------------------------------- /mybatis-plugin/src/main/java/com/github/plugin/id/PropertyColumnPair.java: -------------------------------------------------------------------------------- 1 | package com.github.plugin.id; 2 | 3 | /** 4 | * User: 吴海旭 5 | * Date: 2017-06-28 6 | * Time: 下午5:34 7 | */ 8 | public class PropertyColumnPair { 9 | 10 | private String property; 11 | private String column; 12 | 13 | public String getProperty() { 14 | return property; 15 | } 16 | 17 | public void setProperty(String property) { 18 | this.property = property; 19 | } 20 | 21 | public String getColumn() { 22 | return column; 23 | } 24 | 25 | public void setColumn(String column) { 26 | this.column = column; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /mybatis-plugin/src/main/java/com/github/plugin/id/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * AutoIncrementKeyPlugin插件使用 4 | 改变带有自增id的insert语句的执行行为, 由数据库执行后返回id的方式修改为在执行前设置id的值, 添加insert id列值的方式。 5 | 6 | * User: 吴海旭 7 | * Date: 2017-06-28 8 | * Time: 下午5:09 9 | */ 10 | package com.github.plugin.id; -------------------------------------------------------------------------------- /mybatis-plugin/src/main/java/com/github/plugin/monitor/DefaultMonitor.java: -------------------------------------------------------------------------------- 1 | package com.github.plugin.monitor; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | /** 7 | * User: 吴海旭 8 | * Date: 2017-06-29 9 | * Time: 下午1:24 10 | */ 11 | public class DefaultMonitor implements Monitor { 12 | 13 | private Logger logger = LoggerFactory.getLogger(DefaultMonitor.class); 14 | 15 | @Override 16 | public void alarm(String msg) { 17 | logger.info(msg); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /mybatis-plugin/src/main/java/com/github/plugin/monitor/Monitor.java: -------------------------------------------------------------------------------- 1 | package com.github.plugin.monitor; 2 | 3 | /** 4 | * User: 吴海旭 5 | * Date: 2017-06-29 6 | * Time: 下午1:24 7 | */ 8 | public interface Monitor { 9 | 10 | /** 11 | * 报警 12 | * @param msg 报警内容 13 | */ 14 | void alarm(String msg); 15 | } 16 | -------------------------------------------------------------------------------- /mybatis-plugin/src/main/java/com/github/plugin/rw/DataSourceSwitchFactoryBean.java: -------------------------------------------------------------------------------- 1 | package com.github.plugin.rw; 2 | 3 | import com.github.plugin.PluginUtils; 4 | import org.springframework.beans.factory.FactoryBean; 5 | 6 | import javax.sql.DataSource; 7 | import java.lang.reflect.InvocationHandler; 8 | import java.lang.reflect.Method; 9 | import java.lang.reflect.Proxy; 10 | import java.util.Set; 11 | 12 | /** 13 | * User: 吴海旭 14 | * Date: 2017-06-30 15 | * Time: 上午10:50 16 | */ 17 | public class DataSourceSwitchFactoryBean implements FactoryBean { 18 | private DataSource dataSourceMajor; 19 | private DataSource dataSourceMinor; 20 | private Set minorSqlIds; 21 | 22 | public void setDataSourceMajor(DataSource dataSourceMajor) { 23 | this.dataSourceMajor = dataSourceMajor; 24 | } 25 | 26 | public void setDataSourceMinor(DataSource dataSourceMinor) { 27 | this.dataSourceMinor = dataSourceMinor; 28 | } 29 | 30 | public void setMinorSqlIds(Set minorSqlIds) { 31 | this.minorSqlIds = minorSqlIds; 32 | } 33 | 34 | @Override 35 | public DataSource getObject() throws Exception { 36 | return (DataSource) Proxy.newProxyInstance( 37 | this.getClass().getClassLoader(), 38 | new Class[]{DataSource.class}, 39 | new DataSourceInvocationHandler()); 40 | } 41 | 42 | @Override 43 | public Class getObjectType() { 44 | return DataSource.class; 45 | } 46 | 47 | @Override 48 | public boolean isSingleton() { 49 | return true; 50 | } 51 | 52 | private class DataSourceInvocationHandler implements InvocationHandler { 53 | public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 54 | String sqlId = PluginUtils.getSqlId(); 55 | boolean isSlaveSqlId = sqlId != null && minorSqlIds != null && minorSqlIds.contains(sqlId); 56 | DataSource dataSource = isSlaveSqlId ? dataSourceMinor : dataSourceMajor; 57 | return method.invoke(dataSource, args); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /mybatis-plugin/src/main/java/com/github/plugin/rw/DataSourceSwitchInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.github.plugin.rw; 2 | 3 | import com.github.plugin.PluginUtils; 4 | import org.apache.ibatis.cache.CacheKey; 5 | import org.apache.ibatis.executor.Executor; 6 | import org.apache.ibatis.mapping.BoundSql; 7 | import org.apache.ibatis.mapping.MappedStatement; 8 | import org.apache.ibatis.plugin.*; 9 | import org.apache.ibatis.session.ResultHandler; 10 | import org.apache.ibatis.session.RowBounds; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | 14 | import java.util.Properties; 15 | 16 | /** 17 | * 在执行sql前将sqlId放入到ThreadLocal中, 后面DataSourceSwitchFactoryBean会根据此sqlId来判断使用那个数据源 18 | * 19 | * User: 吴海旭 20 | * Date: 2017-06-30 21 | * Time: 下午1:12 22 | */ 23 | @Intercepts({ 24 | @Signature( 25 | type = Executor.class, 26 | method = "query", 27 | args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}), 28 | @Signature( 29 | type = Executor.class, 30 | method = "query", 31 | args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}), 32 | @Signature( 33 | type = Executor.class, 34 | method = "update", 35 | args = {MappedStatement.class, Object.class}) 36 | }) 37 | public class DataSourceSwitchInterceptor implements Interceptor { 38 | 39 | private Logger logger = LoggerFactory.getLogger(DataSourceSwitchInterceptor.class); 40 | 41 | public Object intercept(Invocation invocation) throws Throwable { 42 | MappedStatement mappedStatement = (MappedStatement)invocation.getArgs()[0]; 43 | String sqlId = mappedStatement.getId(); 44 | PluginUtils.setSqlId(sqlId); 45 | logger.debug("DataSourceSwitchInterceptor intercept {}", sqlId); 46 | try { 47 | return invocation.proceed(); 48 | } finally { 49 | PluginUtils.clearSqlId(); 50 | } 51 | } 52 | 53 | public Object plugin(Object target) { 54 | return Plugin.wrap(target, this); 55 | } 56 | 57 | public void setProperties(Properties propertiesArg) { 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /mybatis-plugin/src/main/java/com/github/plugin/rw/plan1/DataSource.java: -------------------------------------------------------------------------------- 1 | package com.github.plugin.rw.plan1; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * 10 | * 编译器将把注释记录在类文件中,在运行时 VM 将保留注释,因此可以反射性地读取。 11 | * User: 吴海旭 12 | * Date: 2017-07-01 13 | * Time: 下午4:00 14 | */ 15 | @Retention(RetentionPolicy.RUNTIME) 16 | @Target(ElementType.METHOD) 17 | public @interface DataSource { 18 | 19 | DynamicDataSourceGlobal value() default DynamicDataSourceGlobal.READ; 20 | } 21 | -------------------------------------------------------------------------------- /mybatis-plugin/src/main/java/com/github/plugin/rw/plan1/DynamicDataSource.java: -------------------------------------------------------------------------------- 1 | package com.github.plugin.rw.plan1; 2 | 3 | import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; 4 | 5 | import java.util.HashMap; 6 | import java.util.List; 7 | import java.util.Map; 8 | import java.util.concurrent.ThreadLocalRandom; 9 | import java.util.concurrent.atomic.AtomicLong; 10 | import java.util.concurrent.locks.Lock; 11 | import java.util.concurrent.locks.ReentrantLock; 12 | 13 | /** 14 | * User: 吴海旭 15 | * Date: 2017-07-01 16 | * Time: 下午4:26 17 | */ 18 | public class DynamicDataSource extends AbstractRoutingDataSource { 19 | 20 | private Object writeDataSource; // 写数据源 21 | private List readDataSources; // 多个读数据源 22 | private int readDataSourceSize; // 读数据源个数 23 | private int readDataSourcePollPattern = 0; // 获取读数据源方式,0:随机,1:轮询 24 | private AtomicLong counter = new AtomicLong(0); 25 | private static final Long MAX_POOL = Long.MAX_VALUE; 26 | private final Lock lock = new ReentrantLock(); 27 | 28 | @Override 29 | protected Object determineCurrentLookupKey() { 30 | DynamicDataSourceGlobal dynamicDataSourceGlobal = DynamicDataSourceHolder.getDataSource(); 31 | 32 | if(dynamicDataSourceGlobal == null 33 | || dynamicDataSourceGlobal == DynamicDataSourceGlobal.WRITE 34 | || readDataSourceSize <= 0) { 35 | return DynamicDataSourceGlobal.WRITE.name(); 36 | } 37 | 38 | int index = 1; 39 | 40 | if(readDataSourcePollPattern == 1) { 41 | //轮询方式 42 | long currValue = counter.incrementAndGet(); 43 | if((currValue + 1) >= MAX_POOL) { 44 | try { 45 | lock.lock(); 46 | if((currValue + 1) >= MAX_POOL) { 47 | counter.set(0); 48 | } 49 | } finally { 50 | lock.unlock(); 51 | } 52 | } 53 | index = (int) (currValue % readDataSourceSize); 54 | } else { 55 | //随机方式 56 | index = ThreadLocalRandom.current().nextInt(0, readDataSourceSize); 57 | } 58 | return dynamicDataSourceGlobal.name() + index; 59 | } 60 | 61 | @Override 62 | public void afterPropertiesSet() { 63 | if (this.writeDataSource == null) { 64 | throw new IllegalArgumentException("Property 'writeDataSource' is required"); 65 | } 66 | setDefaultTargetDataSource(writeDataSource); 67 | Map targetDataSources = new HashMap<>(); 68 | targetDataSources.put(DynamicDataSourceGlobal.WRITE.name(), writeDataSource); 69 | if (this.readDataSources == null) { 70 | readDataSourceSize = 0; 71 | } else { 72 | for(int i=0; i readDataSources) { 86 | this.readDataSources = readDataSources; 87 | } 88 | 89 | public void setReadDataSourcePollPattern(int readDataSourcePollPattern) { 90 | this.readDataSourcePollPattern = readDataSourcePollPattern; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /mybatis-plugin/src/main/java/com/github/plugin/rw/plan1/DynamicDataSourceAspect.java: -------------------------------------------------------------------------------- 1 | package com.github.plugin.rw.plan1; 2 | 3 | import org.aspectj.lang.JoinPoint; 4 | import org.aspectj.lang.annotation.After; 5 | import org.aspectj.lang.annotation.Aspect; 6 | import org.aspectj.lang.annotation.Before; 7 | import org.aspectj.lang.annotation.Pointcut; 8 | import org.aspectj.lang.reflect.MethodSignature; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | 12 | import java.lang.reflect.Method; 13 | 14 | /** 15 | * User: 吴海旭 16 | * Date: 2017-07-01 17 | * Time: 下午4:39 18 | */ 19 | @Aspect 20 | public class DynamicDataSourceAspect { 21 | 22 | private static final Logger logger = LoggerFactory.getLogger(DynamicDataSourceAspect.class); 23 | 24 | @Pointcut("execution(* com.github.*.*(..))") 25 | public void pointCut() { 26 | 27 | } 28 | 29 | @Before(value = "pointCut()") 30 | public void before(JoinPoint point) { 31 | Object target = point.getTarget(); 32 | String methodName = point.getSignature().getName(); 33 | Class[] clazz = target.getClass().getInterfaces(); 34 | Class[] parameterTypes = ((MethodSignature) point.getSignature()).getMethod().getParameterTypes(); 35 | try { 36 | Method method = clazz[0].getMethod(methodName, parameterTypes); 37 | if (method != null && method.isAnnotationPresent(DataSource.class)) { 38 | DataSource data = method.getAnnotation(DataSource.class); 39 | DynamicDataSourceHolder.putDataSource(data.value()); 40 | } 41 | } catch (Exception e) { 42 | logger.error(String.format("Choose DataSource error, method:%s, msg:%s", methodName, e.getMessage())); 43 | } 44 | } 45 | 46 | @After(value = "pointCut()") 47 | public void after(JoinPoint point) { 48 | DynamicDataSourceHolder.clear(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /mybatis-plugin/src/main/java/com/github/plugin/rw/plan1/DynamicDataSourceGlobal.java: -------------------------------------------------------------------------------- 1 | package com.github.plugin.rw.plan1; 2 | 3 | /** 4 | * User: 吴海旭 5 | * Date: 2017-07-01 6 | * Time: 下午4:00 7 | */ 8 | public enum DynamicDataSourceGlobal { 9 | READ, WRITE; 10 | } 11 | -------------------------------------------------------------------------------- /mybatis-plugin/src/main/java/com/github/plugin/rw/plan1/DynamicDataSourceHolder.java: -------------------------------------------------------------------------------- 1 | package com.github.plugin.rw.plan1; 2 | 3 | /** 4 | * User: 吴海旭 5 | * Date: 2017-07-01 6 | * Time: 下午4:03 7 | */ 8 | public class DynamicDataSourceHolder { 9 | 10 | private static ThreadLocal holder = new ThreadLocal<>(); 11 | 12 | public static void putDataSource(DynamicDataSourceGlobal dataSourceGlobal) { 13 | holder.set(dataSourceGlobal); 14 | } 15 | 16 | public static DynamicDataSourceGlobal getDataSource() { 17 | return holder.get(); 18 | } 19 | 20 | public static void clear() { 21 | holder.remove(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /mybatis-plugin/src/main/java/com/github/plugin/rw/plan2/ConnectionProxy.java: -------------------------------------------------------------------------------- 1 | package com.github.plugin.rw.plan2; 2 | 3 | import java.sql.Connection; 4 | 5 | /** 6 | * User: 吴海旭 7 | * Date: 2017-07-01 8 | * Time: 下午5:27 9 | */ 10 | public interface ConnectionProxy extends Connection { 11 | 12 | /** 13 | * 根据key路由到正确的connection 14 | * @param key 15 | * @return 16 | */ 17 | Connection getTargetConnection(String key); 18 | } 19 | -------------------------------------------------------------------------------- /mybatis-plugin/src/main/java/com/github/plugin/rw/plan2/DynamicPlugin.java: -------------------------------------------------------------------------------- 1 | package com.github.plugin.rw.plan2; 2 | 3 | import com.github.base.util.ReflectUtil; 4 | import org.apache.ibatis.executor.statement.RoutingStatementHandler; 5 | import org.apache.ibatis.executor.statement.StatementHandler; 6 | import org.apache.ibatis.mapping.MappedStatement; 7 | import org.apache.ibatis.mapping.SqlCommandType; 8 | import org.apache.ibatis.plugin.*; 9 | 10 | import java.sql.Connection; 11 | import java.util.Properties; 12 | 13 | /** 14 | * User: 吴海旭 15 | * Date: 2017-07-01 16 | * Time: 下午5:38 17 | */ 18 | @Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class})}) 19 | public class DynamicPlugin implements Interceptor { 20 | @Override 21 | public Object intercept(Invocation invocation) throws Throwable { 22 | //如果是采用了我们代理,则路由 数据源 23 | Connection conn = (Connection)invocation.getArgs()[0]; 24 | if(conn instanceof ConnectionProxy){ 25 | StatementHandler statementHandler = (StatementHandler) invocation 26 | .getTarget(); 27 | 28 | MappedStatement mappedStatement = null; 29 | if (statementHandler instanceof RoutingStatementHandler) { 30 | StatementHandler delegate = (StatementHandler) ReflectUtil 31 | .getFieldValue(statementHandler, "delegate"); 32 | mappedStatement = (MappedStatement) ReflectUtil.getFieldValue( 33 | delegate, "mappedStatement"); 34 | } else { 35 | mappedStatement = (MappedStatement) ReflectUtil.getFieldValue( 36 | statementHandler, "mappedStatement"); 37 | } 38 | String key = AbstractDynamicDataSourceProxy.WRITE; 39 | 40 | if(mappedStatement.getSqlCommandType() == SqlCommandType.SELECT){ 41 | key = AbstractDynamicDataSourceProxy.READ; 42 | }else{ 43 | key = AbstractDynamicDataSourceProxy.WRITE; 44 | } 45 | 46 | ConnectionProxy connectionProxy = (ConnectionProxy)conn; 47 | connectionProxy.getTargetConnection(key); 48 | 49 | } 50 | 51 | return invocation.proceed(); 52 | } 53 | 54 | @Override 55 | public Object plugin(Object target) { 56 | return Plugin.wrap(target, this); 57 | } 58 | 59 | @Override 60 | public void setProperties(Properties properties) { 61 | 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /mybatis-plugin/src/main/java/com/github/plugin/rw/plan2/DynamicRoutingDataSourceProxy.java: -------------------------------------------------------------------------------- 1 | package com.github.plugin.rw.plan2; 2 | 3 | import javax.sql.DataSource; 4 | import java.util.concurrent.ThreadLocalRandom; 5 | import java.util.concurrent.atomic.AtomicLong; 6 | import java.util.concurrent.locks.Lock; 7 | import java.util.concurrent.locks.ReentrantLock; 8 | 9 | /** 10 | * User: 吴海旭 11 | * Date: 2017-07-01 12 | * Time: 下午5:37 13 | */ 14 | public class DynamicRoutingDataSourceProxy extends AbstractDynamicDataSourceProxy { 15 | private AtomicLong counter = new AtomicLong(0); 16 | 17 | private static final Long MAX_POOL = Long.MAX_VALUE; 18 | 19 | private final Lock lock = new ReentrantLock(); 20 | 21 | @Override 22 | protected DataSource loadReadDataSource() { 23 | int index = 1; 24 | 25 | if(getReadDataSourcePollPattern() == 1) { 26 | //轮询方式 27 | long currValue = counter.incrementAndGet(); 28 | if((currValue + 1) >= MAX_POOL) { 29 | try { 30 | lock.lock(); 31 | if((currValue + 1) >= MAX_POOL) { 32 | counter.set(0); 33 | } 34 | } finally { 35 | lock.unlock(); 36 | } 37 | } 38 | index = (int) (currValue % getReadDsSize()); 39 | } else { 40 | //随机方式 41 | index = ThreadLocalRandom.current().nextInt(0, getReadDsSize()); 42 | } 43 | return getResolvedReadDataSources().get(index); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /mybatis-plugin/src/main/java/com/github/plugin/rw/plan3/DynamicDataSource.java: -------------------------------------------------------------------------------- 1 | package com.github.plugin.rw.plan3; 2 | 3 | import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; 4 | 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | 8 | /** 9 | * User: 吴海旭 10 | * Date: 2017-07-01 11 | * Time: 下午6:04 12 | */ 13 | public class DynamicDataSource extends AbstractRoutingDataSource { 14 | 15 | private Object writeDataSource; //写数据源 16 | 17 | private Object readDataSource; //读数据源 18 | 19 | @Override 20 | public void afterPropertiesSet() { 21 | if (this.writeDataSource == null) { 22 | throw new IllegalArgumentException("Property 'writeDataSource' is required"); 23 | } 24 | setDefaultTargetDataSource(writeDataSource); 25 | Map targetDataSources = new HashMap<>(); 26 | targetDataSources.put(DynamicDataSourceGlobal.WRITE.name(), writeDataSource); 27 | if(readDataSource != null) { 28 | targetDataSources.put(DynamicDataSourceGlobal.READ.name(), readDataSource); 29 | } 30 | setTargetDataSources(targetDataSources); 31 | super.afterPropertiesSet(); 32 | } 33 | 34 | @Override 35 | protected Object determineCurrentLookupKey() { 36 | DynamicDataSourceGlobal dynamicDataSourceGlobal = DynamicDataSourceHolder.getDataSource(); 37 | 38 | if(dynamicDataSourceGlobal == null 39 | || dynamicDataSourceGlobal == DynamicDataSourceGlobal.WRITE) { 40 | return DynamicDataSourceGlobal.WRITE.name(); 41 | } 42 | 43 | return DynamicDataSourceGlobal.READ.name(); 44 | } 45 | 46 | public void setWriteDataSource(Object writeDataSource) { 47 | this.writeDataSource = writeDataSource; 48 | } 49 | 50 | public Object getWriteDataSource() { 51 | return writeDataSource; 52 | } 53 | 54 | public Object getReadDataSource() { 55 | return readDataSource; 56 | } 57 | 58 | public void setReadDataSource(Object readDataSource) { 59 | this.readDataSource = readDataSource; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /mybatis-plugin/src/main/java/com/github/plugin/rw/plan3/DynamicDataSourceGlobal.java: -------------------------------------------------------------------------------- 1 | package com.github.plugin.rw.plan3; 2 | 3 | /** 4 | * User: 吴海旭 5 | * Date: 2017-07-01 6 | * Time: 下午4:00 7 | */ 8 | public enum DynamicDataSourceGlobal { 9 | READ, WRITE; 10 | } 11 | -------------------------------------------------------------------------------- /mybatis-plugin/src/main/java/com/github/plugin/rw/plan3/DynamicDataSourceHolder.java: -------------------------------------------------------------------------------- 1 | package com.github.plugin.rw.plan3; 2 | 3 | /** 4 | * User: 吴海旭 5 | * Date: 2017-07-01 6 | * Time: 下午4:03 7 | */ 8 | public class DynamicDataSourceHolder { 9 | 10 | private static ThreadLocal holder = new ThreadLocal<>(); 11 | 12 | public static void putDataSource(DynamicDataSourceGlobal dataSourceGlobal) { 13 | holder.set(dataSourceGlobal); 14 | } 15 | 16 | public static DynamicDataSourceGlobal getDataSource() { 17 | return holder.get(); 18 | } 19 | 20 | public static void clear() { 21 | holder.remove(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /mybatis-plugin/src/main/java/com/github/plugin/rw/plan3/DynamicDataSourceTransactionManager.java: -------------------------------------------------------------------------------- 1 | package com.github.plugin.rw.plan3; 2 | 3 | import org.springframework.jdbc.datasource.DataSourceTransactionManager; 4 | import org.springframework.transaction.TransactionDefinition; 5 | 6 | /** 7 | * User: 吴海旭 8 | * Date: 2017-07-01 9 | * Time: 下午6:16 10 | */ 11 | public class DynamicDataSourceTransactionManager extends DataSourceTransactionManager { 12 | 13 | /** 14 | * 只读事务到读库,读写事务到写库 15 | * @param transaction 16 | * @param definition 17 | */ 18 | @Override 19 | protected void doBegin(Object transaction, TransactionDefinition definition) { 20 | 21 | //设置数据源 22 | boolean readOnly = definition.isReadOnly(); 23 | if(readOnly) { 24 | DynamicDataSourceHolder.putDataSource(DynamicDataSourceGlobal.READ); 25 | } else { 26 | DynamicDataSourceHolder.putDataSource(DynamicDataSourceGlobal.WRITE); 27 | } 28 | super.doBegin(transaction, definition); 29 | } 30 | 31 | /** 32 | * 清理本地线程的数据源 33 | * @param transaction 34 | */ 35 | @Override 36 | protected void doCleanupAfterCompletion(Object transaction) { 37 | super.doCleanupAfterCompletion(transaction); 38 | DynamicDataSourceHolder.clear(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /mybatis-plugin/src/main/java/com/github/plugin/rw/plan3/DynamicPlugin.java: -------------------------------------------------------------------------------- 1 | package com.github.plugin.rw.plan3; 2 | 3 | import org.apache.ibatis.executor.Executor; 4 | import org.apache.ibatis.executor.keygen.SelectKeyGenerator; 5 | import org.apache.ibatis.mapping.BoundSql; 6 | import org.apache.ibatis.mapping.MappedStatement; 7 | import org.apache.ibatis.mapping.SqlCommandType; 8 | import org.apache.ibatis.plugin.*; 9 | import org.apache.ibatis.session.ResultHandler; 10 | import org.apache.ibatis.session.RowBounds; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | import org.springframework.transaction.support.TransactionSynchronizationManager; 14 | 15 | import java.util.Locale; 16 | import java.util.Map; 17 | import java.util.Properties; 18 | import java.util.concurrent.ConcurrentHashMap; 19 | 20 | /** 21 | * User: 吴海旭 22 | * Date: 2017-07-01 23 | * Time: 下午6:18 24 | */ 25 | @Intercepts({ 26 | @Signature(type = Executor.class, method = "update", args = { 27 | MappedStatement.class, Object.class }), 28 | @Signature(type = Executor.class, method = "query", args = { 29 | MappedStatement.class, Object.class, RowBounds.class, 30 | ResultHandler.class }) }) 31 | public class DynamicPlugin implements Interceptor { 32 | protected static final Logger logger = LoggerFactory.getLogger(DynamicPlugin.class); 33 | 34 | private static final String REGEX = ".*insert\\u0020.*|.*delete\\u0020.*|.*update\\u0020.*"; 35 | 36 | private static final Map cacheMap = new ConcurrentHashMap<>(); 37 | 38 | @Override 39 | public Object intercept(Invocation invocation) throws Throwable { 40 | 41 | boolean synchronizationActive = TransactionSynchronizationManager.isSynchronizationActive(); 42 | if(!synchronizationActive) { 43 | Object[] objects = invocation.getArgs(); 44 | MappedStatement ms = (MappedStatement) objects[0]; 45 | 46 | DynamicDataSourceGlobal dynamicDataSourceGlobal = null; 47 | 48 | if((dynamicDataSourceGlobal = cacheMap.get(ms.getId())) == null) { 49 | //读方法 50 | if(ms.getSqlCommandType().equals(SqlCommandType.SELECT)) { 51 | //!selectKey 为自增id查询主键(SELECT LAST_INSERT_ID() )方法,使用主库 52 | if(ms.getId().contains(SelectKeyGenerator.SELECT_KEY_SUFFIX)) { 53 | dynamicDataSourceGlobal = DynamicDataSourceGlobal.WRITE; 54 | } else { 55 | BoundSql boundSql = ms.getSqlSource().getBoundSql(objects[1]); 56 | String sql = boundSql.getSql().toLowerCase(Locale.CHINA).replaceAll("[\\t\\n\\r]", " "); 57 | if(sql.matches(REGEX)) { 58 | dynamicDataSourceGlobal = DynamicDataSourceGlobal.WRITE; 59 | } else { 60 | dynamicDataSourceGlobal = DynamicDataSourceGlobal.READ; 61 | } 62 | } 63 | }else{ 64 | dynamicDataSourceGlobal = DynamicDataSourceGlobal.WRITE; 65 | } 66 | logger.warn("设置方法[{}] use [{}] Strategy, SqlCommandType [{}]..", ms.getId(), dynamicDataSourceGlobal.name(), ms.getSqlCommandType().name()); 67 | cacheMap.put(ms.getId(), dynamicDataSourceGlobal); 68 | } 69 | DynamicDataSourceHolder.putDataSource(dynamicDataSourceGlobal); 70 | } 71 | 72 | return invocation.proceed(); 73 | } 74 | 75 | @Override 76 | public Object plugin(Object target) { 77 | if (target instanceof Executor) { 78 | return Plugin.wrap(target, this); 79 | } else { 80 | return target; 81 | } 82 | } 83 | 84 | @Override 85 | public void setProperties(Properties properties) { 86 | // 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /mybatis-plugin/src/main/resources/plugin/rw/plan1/rw2.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | classpath:mapper/*.xml 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /mybatis-plugin/src/main/resources/plugin/rw/rwDbConfig.properties: -------------------------------------------------------------------------------- 1 | read1.jdbc.url=jdbc:mysql://localhost/mybatis?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC 2 | read1.jdbc.username=root 3 | read1.jdbc.password=123456 4 | 5 | read2.jdbc.url=jdbc:mysql://localhost/mybatis?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC 6 | read2.jdbc.username=root 7 | read2.jdbc.password=123456 8 | 9 | write.jdbc.url=jdbc:mysql://localhost/mybatis?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC 10 | write.jdbc.username=root 11 | write.jdbc.password=123456 -------------------------------------------------------------------------------- /mybatis-plugin/src/test/java/com/github/plugin/id/AtomicLongIDGen.java: -------------------------------------------------------------------------------- 1 | package com.github.plugin.id; 2 | 3 | import java.util.concurrent.atomic.AtomicLong; 4 | 5 | /** 6 | * 7 | * 仅限测试使用 8 | * 9 | * User: 吴海旭 10 | * Date: 2017-06-28 11 | * Time: 下午6:09 12 | */ 13 | public class AtomicLongIDGen implements IDGen { 14 | 15 | public static AtomicLong identity = new AtomicLong(10); 16 | 17 | public long newId(String tableName) { 18 | return identity.incrementAndGet(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /mybatis-plugin/src/test/java/com/github/plugin/id/AutoIncrementKeyPluginTest.java: -------------------------------------------------------------------------------- 1 | package com.github.plugin.id; 2 | 3 | import com.github.base.bean.Student; 4 | import com.github.base.mapper.StudentMapper; 5 | import org.apache.ibatis.session.SqlSession; 6 | import org.junit.After; 7 | import org.junit.Before; 8 | import org.junit.Test; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | 12 | /** 13 | * User: 吴海旭 14 | * Date: 2017-06-28 15 | * Time: 下午6:09 16 | */ 17 | public class AutoIncrementKeyPluginTest { 18 | 19 | private Logger logger = LoggerFactory.getLogger(AutoIncrementKeyPluginTest.class); 20 | private SqlSession sqlSession = null; 21 | 22 | @Before 23 | public void setUp() { 24 | sqlSession = MyBatisConfigHelper.getSqlSession(); 25 | deleteAll(); 26 | } 27 | 28 | @After 29 | public void destroy() { 30 | if (sqlSession != null) { 31 | sqlSession.close(); 32 | } 33 | } 34 | 35 | public void deleteAll() { 36 | StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); 37 | mapper.deleteAll(); 38 | } 39 | 40 | @Test 41 | public void testInsert() { 42 | StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); 43 | Student student = new Student(); 44 | student.setId(10L); 45 | student.setName("jack"); 46 | mapper.insert(student); 47 | 48 | Student student2 = new Student(); 49 | student2.setName("lucy"); 50 | mapper.insert(student2); 51 | 52 | sqlSession.commit(); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /mybatis-plugin/src/test/java/com/github/plugin/id/MyBatisConfigHelper.java: -------------------------------------------------------------------------------- 1 | package com.github.plugin.id; 2 | 3 | import org.apache.ibatis.io.Resources; 4 | import org.apache.ibatis.session.SqlSession; 5 | import org.apache.ibatis.session.SqlSessionFactory; 6 | import org.apache.ibatis.session.SqlSessionFactoryBuilder; 7 | 8 | import java.io.IOException; 9 | import java.io.InputStream; 10 | 11 | /** 12 | * User: 吴海旭 13 | * Date: 2017-06-28 14 | * Time: 下午6:20 15 | */ 16 | public class MyBatisConfigHelper { 17 | 18 | private static SqlSessionFactory sqlSessionFactory; 19 | 20 | static { 21 | String resource = "mybatis-config/idConfig.xml"; 22 | InputStream in = null; 23 | try { 24 | in = Resources.getResourceAsStream(resource); 25 | } catch (IOException e) { 26 | e.printStackTrace(); 27 | } 28 | sqlSessionFactory = new SqlSessionFactoryBuilder().build(in); 29 | } 30 | 31 | public static SqlSessionFactory getSqlSessionFactory() { 32 | return sqlSessionFactory; 33 | } 34 | 35 | public static SqlSession getSqlSession() { 36 | return sqlSessionFactory.openSession(); 37 | } 38 | 39 | public static SqlSession getSqlSession(boolean autoCommit) { 40 | return sqlSessionFactory.openSession(autoCommit); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /mybatis-plugin/src/test/java/com/github/plugin/monitor/MonitorConfigHelper.java: -------------------------------------------------------------------------------- 1 | package com.github.plugin.monitor; 2 | 3 | import org.apache.ibatis.io.Resources; 4 | import org.apache.ibatis.session.SqlSession; 5 | import org.apache.ibatis.session.SqlSessionFactory; 6 | import org.apache.ibatis.session.SqlSessionFactoryBuilder; 7 | 8 | import java.io.IOException; 9 | import java.io.InputStream; 10 | 11 | /** 12 | * User: 吴海旭 13 | * Date: 2017-06-28 14 | * Time: 下午6:20 15 | */ 16 | public class MonitorConfigHelper { 17 | 18 | private static SqlSessionFactory sqlSessionFactory; 19 | 20 | static { 21 | String resource = "mybatis-config/monitorConfig.xml"; 22 | InputStream in = null; 23 | try { 24 | in = Resources.getResourceAsStream(resource); 25 | } catch (IOException e) { 26 | e.printStackTrace(); 27 | } 28 | sqlSessionFactory = new SqlSessionFactoryBuilder().build(in); 29 | } 30 | 31 | public static SqlSessionFactory getSqlSessionFactory() { 32 | return sqlSessionFactory; 33 | } 34 | 35 | public static SqlSession getSqlSession() { 36 | return sqlSessionFactory.openSession(); 37 | } 38 | 39 | public static SqlSession getSqlSession(boolean autoCommit) { 40 | return sqlSessionFactory.openSession(autoCommit); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /mybatis-plugin/src/test/java/com/github/plugin/monitor/MonitorInterceptorTest.java: -------------------------------------------------------------------------------- 1 | package com.github.plugin.monitor; 2 | 3 | import com.github.base.bean.Student; 4 | import com.github.base.mapper.StudentMapper; 5 | import org.apache.ibatis.session.SqlSession; 6 | import org.junit.After; 7 | import org.junit.Before; 8 | import org.junit.Test; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | 12 | /** 13 | * User: 吴海旭 14 | * Date: 2017-06-29 15 | * Time: 下午1:36 16 | */ 17 | public class MonitorInterceptorTest { 18 | 19 | private Logger logger = LoggerFactory.getLogger(MonitorInterceptorTest.class); 20 | private SqlSession sqlSession = null; 21 | 22 | @Before 23 | public void setUp() { 24 | sqlSession = MonitorConfigHelper.getSqlSession(); 25 | deleteAll(); 26 | } 27 | 28 | @After 29 | public void destroy() { 30 | if (sqlSession != null) { 31 | sqlSession.close(); 32 | } 33 | } 34 | 35 | public void deleteAll() { 36 | StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); 37 | mapper.deleteAll(); 38 | } 39 | 40 | @Test 41 | public void testInsert() { 42 | StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); 43 | Student student = new Student(); 44 | student.setName("jack"); 45 | mapper.insert(student); 46 | sqlSession.commit(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /mybatis-plugin/src/test/resources/mybatis-config/idConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 24 | 25 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /mybatis-plugin/src/test/resources/mybatis-config/monitorConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /mybatis-plugin/src/test/resources/mybatis-config/rwConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /mybatis-plugin/src/test/resources/rw/spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | com.github.base.mapper.StudentMapper.selectAll 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | classpath:mapper/*.xml 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /mybatis-spring/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | mybatis 5 | com.github 6 | 1.0-SNAPSHOT 7 | 8 | 4.0.0 9 | mybatis-spring 10 | war 11 | mybatis-spring Maven Webapp 12 | http://maven.apache.org 13 | 14 | 15 | 16 | com.github 17 | mybatis-base 18 | 1.0-SNAPSHOT 19 | 20 | 21 | org.mybatis 22 | mybatis-spring 23 | 24 | 25 | com.github.pagehelper 26 | pagehelper 27 | 28 | 29 | tk.mybatis 30 | mapper 31 | 32 | 33 | javax.persistence 34 | persistence-api 35 | 36 | 37 | org.springframework 38 | spring-webmvc 39 | 40 | 41 | org.springframework 42 | spring-jdbc 43 | 44 | 45 | javax.servlet 46 | jstl 47 | 48 | 49 | org.aspectj 50 | aspectjrt 51 | 52 | 53 | org.aspectj 54 | aspectjweaver 55 | 56 | 57 | commons-dbcp 58 | commons-dbcp 59 | 60 | 61 | 62 | mybatis-spring 63 | 64 | 65 | -------------------------------------------------------------------------------- /mybatis-spring/src/main/java/com/github/spring/common/CommonMapper.java: -------------------------------------------------------------------------------- 1 | package com.github.spring.common; 2 | 3 | import tk.mybatis.mapper.common.IdsMapper; 4 | import tk.mybatis.mapper.common.Mapper; 5 | import tk.mybatis.mapper.common.MySqlMapper; 6 | 7 | /** 8 | * User: 吴海旭 9 | * Date: 2017-06-25 10 | * Time: 下午3:35 11 | */ 12 | public interface CommonMapper extends Mapper, IdsMapper, MySqlMapper { 13 | } 14 | -------------------------------------------------------------------------------- /mybatis-spring/src/main/java/com/github/spring/mapper/UserLoginMapper.java: -------------------------------------------------------------------------------- 1 | package com.github.spring.mapper; 2 | 3 | import com.github.spring.common.CommonMapper; 4 | import com.github.spring.model.UserLogin; 5 | 6 | /** 7 | * User: 吴海旭 8 | * Date: 2017-06-25 9 | * Time: 下午5:10 10 | */ 11 | public interface UserLoginMapper extends CommonMapper { 12 | } 13 | -------------------------------------------------------------------------------- /mybatis-spring/src/main/java/com/github/spring/model/UserLogin.java: -------------------------------------------------------------------------------- 1 | package com.github.spring.model; 2 | 3 | import tk.mybatis.mapper.entity.IDynamicTableName; 4 | 5 | import javax.persistence.GeneratedValue; 6 | import javax.persistence.Id; 7 | import javax.persistence.Table; 8 | import javax.persistence.Transient; 9 | import java.io.Serializable; 10 | import java.util.Date; 11 | 12 | @Table(name = "user_login") 13 | public class UserLogin implements Serializable, IDynamicTableName { 14 | private static final long serialVersionUID = -445441931554119345L; 15 | 16 | @Id 17 | @GeneratedValue(generator = "JDBC") 18 | // @OrderBy("desc") 19 | private Long logid; 20 | 21 | private String username; 22 | 23 | private Date logindate; 24 | 25 | private String loginip; 26 | 27 | @Transient 28 | private String dynamicTableName; 29 | 30 | public Long getLogid() { 31 | return logid; 32 | } 33 | 34 | public void setLogid(Long logid) { 35 | this.logid = logid; 36 | } 37 | 38 | public String getUsername() { 39 | return username; 40 | } 41 | 42 | public void setUsername(String username) { 43 | this.username = username == null ? null : username.trim(); 44 | } 45 | 46 | public Date getLogindate() { 47 | return logindate; 48 | } 49 | 50 | public void setLogindate(Date logindate) { 51 | this.logindate = logindate; 52 | } 53 | 54 | public String getLoginip() { 55 | return loginip; 56 | } 57 | 58 | public void setLoginip(String loginip) { 59 | this.loginip = loginip == null ? null : loginip.trim(); 60 | } 61 | 62 | @Override 63 | public String toString() { 64 | return "UserLogin{" + 65 | "logid=" + logid + 66 | ", username='" + username + '\'' + 67 | ", logindate=" + logindate + 68 | ", loginip='" + loginip + '\'' + 69 | '}'; 70 | } 71 | 72 | @Override 73 | public String getDynamicTableName() { 74 | return dynamicTableName; 75 | } 76 | 77 | public void setDynamicTableName(String dynamicTableName) { 78 | this.dynamicTableName = dynamicTableName; 79 | } 80 | } -------------------------------------------------------------------------------- /mybatis-spring/src/main/java/com/github/spring/plugin/PerformanceInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.github.spring.plugin; 2 | 3 | import org.apache.ibatis.cache.CacheKey; 4 | import org.apache.ibatis.executor.Executor; 5 | import org.apache.ibatis.mapping.BoundSql; 6 | import org.apache.ibatis.mapping.MappedStatement; 7 | import org.apache.ibatis.mapping.ParameterMapping; 8 | import org.apache.ibatis.mapping.ParameterMode; 9 | import org.apache.ibatis.plugin.*; 10 | import org.apache.ibatis.reflection.MetaObject; 11 | import org.apache.ibatis.session.Configuration; 12 | import org.apache.ibatis.session.ResultHandler; 13 | import org.apache.ibatis.session.RowBounds; 14 | import org.apache.ibatis.type.TypeHandlerRegistry; 15 | 16 | import java.text.DateFormat; 17 | import java.text.SimpleDateFormat; 18 | import java.util.Date; 19 | import java.util.List; 20 | import java.util.Properties; 21 | 22 | /** 23 | * MyBatis 性能拦截器,用于输出每条 SQL 语句及其执行时间 24 | * 25 | * User: 吴海旭 26 | * Date: 2017-06-18 27 | * Time: 下午7:41 28 | */ 29 | @Intercepts({ 30 | @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}), 31 | @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}) 32 | }) 33 | public class PerformanceInterceptor implements Interceptor { 34 | 35 | private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 36 | 37 | @Override 38 | public Object intercept(Invocation invocation) throws Throwable { 39 | MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0]; 40 | String statementId = mappedStatement.getId(); 41 | Configuration configuration = mappedStatement.getConfiguration(); 42 | Object parameterObject = invocation.getArgs()[1]; 43 | BoundSql boundSql = null; 44 | 45 | if ("query".equals(invocation.getMethod().getName())) { 46 | // Fix bug @See:https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/Interceptor.md 47 | boundSql = (BoundSql) invocation.getArgs()[5]; 48 | } else { 49 | boundSql = mappedStatement.getBoundSql(parameterObject); 50 | } 51 | String sql = getSql(boundSql, parameterObject, configuration); 52 | 53 | long start = System.currentTimeMillis(); 54 | 55 | Object result = invocation.proceed(); 56 | 57 | long end = System.currentTimeMillis(); 58 | long timing = end - start; 59 | 60 | System.out.println("耗时:" + timing + " ms" + " - id:" + statementId + " - Sql:" + sql); 61 | return result; 62 | } 63 | 64 | @Override 65 | public Object plugin(Object target) { 66 | if (target instanceof Executor) { 67 | return Plugin.wrap(target, this); 68 | } 69 | return target; 70 | } 71 | 72 | @Override 73 | public void setProperties(Properties properties) { 74 | 75 | } 76 | 77 | /** 78 | * 获取待执行的sql语句 79 | * @param boundSql 80 | * @param parameterObject 参数对象,如果是多参数就是一个Map,对应着propertyName value 81 | * @param configuration 82 | * @return 83 | */ 84 | private String getSql(BoundSql boundSql, Object parameterObject, Configuration configuration) { 85 | String sql = boundSql.getSql().replaceAll("[\\s]+", " "); 86 | List parameterMappings = boundSql.getParameterMappings(); 87 | TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry(); 88 | if (parameterMappings != null) { 89 | for (int i = 0; i < parameterMappings.size(); i++) { 90 | ParameterMapping parameterMapping = parameterMappings.get(i); 91 | if (parameterMapping.getMode() != ParameterMode.OUT) { 92 | Object value; 93 | String propertyName = parameterMapping.getProperty(); 94 | if (boundSql.hasAdditionalParameter(propertyName)) { 95 | value = boundSql.getAdditionalParameter(propertyName); 96 | } else if (parameterObject == null) { 97 | value = null; 98 | } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) { 99 | // 单个参数,并且类型是typeHandlerRegistry已经存在的 100 | value = parameterObject; 101 | } else { 102 | // 多参数 103 | MetaObject metaObject = configuration.newMetaObject(parameterObject); 104 | value = metaObject.getValue(propertyName); 105 | } 106 | // 把?替换成值 107 | sql = replacePlaceholder(sql, value); 108 | } 109 | } 110 | } 111 | return sql; 112 | } 113 | 114 | private String replacePlaceholder(String sql, Object propertyValue) { 115 | String result; 116 | if (propertyValue != null) { 117 | if (propertyValue instanceof String) { 118 | result = "'" + propertyValue + "'"; 119 | } else if (propertyValue instanceof Date) { 120 | result = "'" + DATE_FORMAT.format(propertyValue) + "'"; 121 | } else { 122 | result = propertyValue.toString(); 123 | } 124 | } else { 125 | result = "null"; 126 | } 127 | return sql.replaceFirst("\\?", result); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /mybatis-spring/src/main/java/com/github/spring/service/RoleService.java: -------------------------------------------------------------------------------- 1 | package com.github.spring.service; 2 | 3 | import com.github.base.bean.Role; 4 | import com.github.base.mapper.RoleMapper; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.stereotype.Service; 7 | 8 | /** 9 | * User: benjamin.wuhaixu 10 | * Date: 2017-12-28 11 | * Time: 2:17 pm 12 | */ 13 | @Service 14 | public class RoleService { 15 | 16 | @Autowired 17 | private RoleMapper roleMapper; 18 | 19 | public Role getRole(Long id) { 20 | return roleMapper.findRoleById(id); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /mybatis-spring/src/main/java/com/github/spring/service/UserLoginService.java: -------------------------------------------------------------------------------- 1 | package com.github.spring.service; 2 | 3 | import com.github.base.bean.User; 4 | import com.github.base.mapper.UserMapper; 5 | import com.github.pagehelper.PageHelper; 6 | import com.github.spring.mapper.UserLoginMapper; 7 | import com.github.spring.model.UserLogin; 8 | import org.apache.ibatis.session.RowBounds; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.stereotype.Service; 11 | import org.springframework.transaction.PlatformTransactionManager; 12 | import org.springframework.transaction.TransactionDefinition; 13 | import org.springframework.transaction.TransactionStatus; 14 | import org.springframework.transaction.annotation.Transactional; 15 | import org.springframework.transaction.support.DefaultTransactionDefinition; 16 | 17 | import java.util.List; 18 | 19 | /** 20 | * User: 吴海旭 21 | * Date: 2017-06-18 22 | * Time: 下午5:29 23 | */ 24 | @Service 25 | public class UserLoginService { 26 | 27 | @Autowired 28 | private UserLoginMapper userLoginMapper; 29 | 30 | @Transactional(readOnly = true) 31 | public List getAllUserLogins() { 32 | return userLoginMapper.selectAll(); 33 | } 34 | 35 | @Transactional(readOnly = true) 36 | public List getUsersByPage(int pageNo, int pageSize) { 37 | PageHelper.startPage(pageNo, pageSize, false); 38 | return userLoginMapper.selectAll(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /mybatis-spring/src/main/java/com/github/spring/service/UserService.java: -------------------------------------------------------------------------------- 1 | package com.github.spring.service; 2 | 3 | import com.github.base.bean.User; 4 | import com.github.base.mapper.UserMapper; 5 | import org.apache.ibatis.session.RowBounds; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Service; 8 | import org.springframework.transaction.PlatformTransactionManager; 9 | import org.springframework.transaction.TransactionDefinition; 10 | import org.springframework.transaction.TransactionStatus; 11 | import org.springframework.transaction.support.DefaultTransactionDefinition; 12 | 13 | import java.util.List; 14 | 15 | /** 16 | * User: 吴海旭 17 | * Date: 2017-06-18 18 | * Time: 下午5:29 19 | */ 20 | @Service 21 | public class UserService { 22 | 23 | @Autowired 24 | private UserMapper userMapper; 25 | @Autowired 26 | private PlatformTransactionManager transactionManager; 27 | 28 | public List getUserList() { 29 | return userMapper.getUserByRowBounds(new RowBounds(0, 10)); 30 | } 31 | 32 | public boolean addUser(User user) { 33 | DefaultTransactionDefinition def = new DefaultTransactionDefinition(); 34 | def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); 35 | 36 | TransactionStatus status = transactionManager.getTransaction(def); 37 | int result; 38 | try { 39 | result = userMapper.insert(user); 40 | } 41 | catch (Exception ex) { 42 | transactionManager.rollback(status); 43 | return false; 44 | } 45 | transactionManager.commit(status); 46 | return result == 1; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /mybatis-spring/src/main/java/com/github/spring/web/UserController.java: -------------------------------------------------------------------------------- 1 | package com.github.spring.web; 2 | 3 | import com.github.base.bean.Role; 4 | import com.github.base.bean.User; 5 | import com.github.spring.service.RoleService; 6 | import com.github.spring.service.UserService; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.stereotype.Controller; 9 | import org.springframework.web.bind.annotation.PathVariable; 10 | import org.springframework.web.bind.annotation.RequestMapping; 11 | import org.springframework.web.bind.annotation.ResponseBody; 12 | import org.springframework.web.servlet.ModelAndView; 13 | 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | 17 | /** 18 | * User: 吴海旭 19 | * Date: 2017-06-17 20 | * Time: 下午10:19 21 | */ 22 | @Controller 23 | @RequestMapping("/user") 24 | public class UserController { 25 | 26 | @Autowired 27 | private UserService userService; 28 | @Autowired 29 | private RoleService roleService; 30 | 31 | @RequestMapping("/show") 32 | public ModelAndView getUserByPage(ModelAndView modelAndView) { 33 | modelAndView.setViewName("user"); 34 | modelAndView.addObject("userList", userService.getUserList()); 35 | Role role = roleService.getRole(1L); 36 | modelAndView.addObject("role", role); 37 | return modelAndView; 38 | } 39 | 40 | @RequestMapping("/add/{userName}") 41 | @ResponseBody 42 | public String add(@PathVariable("userName") String userName) { 43 | User user = new User(); 44 | user.setUserName(userName); 45 | boolean addResult = userService.addUser(user); 46 | if (addResult) { 47 | return "新增成功"; 48 | } else { 49 | return "新增失败"; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /mybatis-spring/src/main/java/com/github/spring/web/UserLoginController.java: -------------------------------------------------------------------------------- 1 | package com.github.spring.web; 2 | 3 | import com.github.base.bean.User; 4 | import com.github.spring.service.UserLoginService; 5 | import com.github.spring.service.UserService; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Controller; 8 | import org.springframework.web.bind.annotation.PathVariable; 9 | import org.springframework.web.bind.annotation.RequestMapping; 10 | import org.springframework.web.bind.annotation.ResponseBody; 11 | import org.springframework.web.servlet.ModelAndView; 12 | 13 | /** 14 | * User: 吴海旭 15 | * Date: 2017-06-17 16 | * Time: 下午10:19 17 | */ 18 | @Controller 19 | @RequestMapping("/userLogin") 20 | public class UserLoginController { 21 | 22 | @Autowired 23 | private UserLoginService userLoginService; 24 | 25 | @RequestMapping("/show") 26 | public ModelAndView getAllUsers(ModelAndView modelAndView) { 27 | modelAndView.setViewName("userLogin"); 28 | modelAndView.addObject("userList", userLoginService.getAllUserLogins()); 29 | return modelAndView; 30 | } 31 | 32 | @RequestMapping("/page/{pageNo}/{pageSize}") 33 | public ModelAndView getUserByPage(ModelAndView modelAndView, @PathVariable("pageNo") int pageNo,@PathVariable("pageSize") int pageSize) { 34 | modelAndView.setViewName("userLogin"); 35 | modelAndView.addObject("userList", userLoginService.getUsersByPage(pageNo, pageSize)); 36 | return modelAndView; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /mybatis-spring/src/main/resources/mybatis-config.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /mybatis-spring/src/main/resources/spring-mvc.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /mybatis-spring/src/main/resources/spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | classpath:mapper/*.xml 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /mybatis-spring/src/main/webapp/WEB-INF/views/user.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | Created by IntelliJ IDEA. 3 | User: wuhaixu 4 | Date: 2017/6/17 5 | Time: 22:20 6 | To change this template use File | Settings | File Templates. 7 | --%> 8 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 9 | <%@taglib prefix="c" uri="http://java.sun.com/jstl/core_rt"%> 10 | 11 | 12 | User 13 | 14 | 15 | 16 |
${user.userName}是${user.role.roleName}

17 |
18 |
role: ${role.roleName}
19 | 20 | 21 | -------------------------------------------------------------------------------- /mybatis-spring/src/main/webapp/WEB-INF/views/userLogin.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | Created by IntelliJ IDEA. 3 | User: wuhaixu 4 | Date: 2017/6/17 5 | Time: 22:20 6 | To change this template use File | Settings | File Templates. 7 | --%> 8 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 9 | <%@taglib prefix="c" uri="http://java.sun.com/jstl/core_rt"%> 10 | 11 | 12 | User 13 | 14 | 15 | 16 |
欢迎:${user.username} 首次登录时间:${user.logindate} 登录ip:${user.loginip}

17 |
18 | 19 | 20 | -------------------------------------------------------------------------------- /mybatis-spring/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | _rootArtifactId_ 7 | 8 | 9 | contextConfigLocation 10 | classpath:spring.xml 11 | 12 | 13 | 14 | encodingFilter 15 | org.springframework.web.filter.CharacterEncodingFilter 16 | 17 | encoding 18 | UTF-8 19 | 20 | 21 | forceEncoding 22 | true 23 | 24 | 25 | 26 | 27 | encodingFilter 28 | /* 29 | 30 | 31 | 32 | springServlet 33 | org.springframework.web.servlet.DispatcherServlet 34 | 35 | contextConfigLocation 36 | classpath:spring-mvc.xml 37 | 38 | 1 39 | 40 | 41 | springServlet 42 | / 43 | 44 | 45 | 46 | org.springframework.web.context.ContextLoaderListener 47 | 48 | 49 | logbackConfigLocation 50 | classpath:logback.xml 51 | 52 | 53 | ch.qos.logback.ext.spring.web.LogbackConfigListener 54 | 55 | 56 | -------------------------------------------------------------------------------- /mybatis-spring/src/main/webapp/index.jsp: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Hello World!

4 | 5 | 6 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.github 8 | mybatis 9 | pom 10 | 1.0-SNAPSHOT 11 | 12 | mybatis-base 13 | mybatis-core 14 | mybatis-spring 15 | mybatis-page 16 | mybatis-order 17 | mybatis-mapper 18 | mybatis-generator 19 | mybatis-plugin 20 | 21 | 22 | 23 | 4.3.9.RELEASE 24 | 25 | 26 | 27 | 28 | 29 | junit 30 | junit 31 | 4.12 32 | test 33 | 34 | 35 | 36 | org.mybatis 37 | mybatis 38 | 3.4.4 39 | 40 | 41 | 42 | org.mybatis 43 | mybatis-spring 44 | 1.3.1 45 | 46 | 47 | 48 | com.github.pagehelper 49 | pagehelper 50 | 5.0.2 51 | 52 | 53 | 54 | tk.mybatis 55 | mapper 56 | 3.4.0 57 | 58 | 59 | javax.persistence 60 | persistence-api 61 | 1.0 62 | 63 | 64 | 65 | tk.mybatis 66 | orderby-helper 67 | 0.0.2 68 | 69 | 70 | 71 | org.mybatis.generator 72 | mybatis-generator-core 73 | 1.3.5 74 | 75 | 76 | 77 | mysql 78 | mysql-connector-java 79 | 6.0.6 80 | runtime 81 | 82 | 83 | 84 | 85 | org.springframework 86 | spring-webmvc 87 | ${spring.version} 88 | 89 | 90 | org.springframework 91 | spring-jdbc 92 | ${spring.version} 93 | 94 | 95 | 96 | javax.servlet 97 | jstl 98 | 1.2 99 | 100 | 101 | 102 | org.aspectj 103 | aspectjrt 104 | 1.7.4 105 | 106 | 107 | org.aspectj 108 | aspectjweaver 109 | 1.7.4 110 | 111 | 112 | 113 | commons-dbcp 114 | commons-dbcp 115 | 1.4 116 | 117 | 118 | 119 | 120 | org.slf4j 121 | slf4j-api 122 | 1.7.21 123 | jar 124 | compile 125 | 126 | 127 | ch.qos.logback 128 | logback-classic 129 | 1.1.7 130 | 131 | 132 | org.logback-extensions 133 | logback-ext-spring 134 | 0.1.4 135 | 136 | 137 | 138 | com.alibaba 139 | fastjson 140 | 1.2.32 141 | 142 | 143 | commons-beanutils 144 | commons-beanutils 145 | 1.9.3 146 | 147 | 148 | 149 | 150 | 151 | mybatis 152 | 153 | 154 | 155 | org.apache.maven.plugins 156 | maven-compiler-plugin 157 | 2.3.2 158 | 159 | 1.8 160 | 1.8 161 | 162 | 163 | 164 | 165 | --------------------------------------------------------------------------------