MybatisConfig.java文件

 import com.alibaba.druid.pool.DruidDataSource;
import com.xman.common.mybatis.SqlMonitorManager;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.util.ClassUtils; import javax.sql.DataSource;
import java.io.IOException;
import java.util.Properties; /**
* Created by chai on 2017/10/11.
*/
@Configuration //用作配置信息
@MapperScan(basePackages = "com.xman.rainbow.dao")
public class MybatisConfig { private static Logger logger = LoggerFactory.getLogger(MybatisConfig.class); @Value("${datasource.driverClass}")
private String jdbcDriver; @Value("${datasource.username}")
private String username; @Value("${datasource.password}")
private String password; @Value("${datasource.jdbcUrl}")
private String jdbcUrl; @Value("${datasource.maxIdle}")
private String maxIdle; //最小、最大
@Value("${datasource.minIdle}")
private String minIdle;
@Value("${datasource.maxActive}")
private int maxActive; @Value("${datasource.maxWait}")
private String maxWait; //配置获取连接等待超时的时间 @Value("${datasource.validationQuery}")
private String validationQuery; @Value("${datasource.testBorrow}")
private boolean testOnBorrow; @Value("${datasource.testOnReturn}")
private boolean testOnReturn; @Value("${datasource.testWhileIdle}")
private boolean testWhileIdle; @Value("${datasource.timeBetweenEvictionRunsMills}")
private long timeBetweenEvictionRunsMills; //配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 @Value("${datasource.minEvictableIdleTimeMillis}")
private long minEvictableTimeMills; //配置一个连接在池中最小生存的时间,单位是毫秒 @Bean //为Spring容器所管理
public DataSource dataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(this.jdbcDriver);
dataSource.setUsername(this.username);
dataSource.setPassword(this.password);
dataSource.setUrl(this.jdbcUrl);
dataSource.setMaxActive(this.maxActive);
dataSource.setValidationQuery(this.validationQuery);
dataSource.setTestOnBorrow(this.testOnBorrow);
dataSource.setTestOnReturn(this.testOnReturn);
dataSource.setTestWhileIdle(this.testWhileIdle);
dataSource.setTimeBetweenConnectErrorMillis(this.timeBetweenEvictionRunsMills);
dataSource.setMinEvictableIdleTimeMillis(minEvictableTimeMills);
return dataSource;
} @Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
logger.debug("start sqlSessionFactory");
final SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();
// 设置datasource
sqlSessionFactory.setDataSource(dataSource());
// 设置mybatis configuration 扫描路径
sqlSessionFactory.setConfigLocation(new ClassPathResource("mybatis-config.xml"));
sqlSessionFactory.setFailFast(true);
//自动扫描entity目录
sqlSessionFactory.setMapperLocations(getResource("mappers", "**/*.xml"));
SqlMonitorManager sqlMonitorManager = new SqlMonitorManager();
Properties properties = new Properties();
properties.setProperty("show_sql", "true");
sqlMonitorManager.setProperties(properties); PageInterceptor pageInterceptor = new PageInterceptor();
Properties property = new Properties();
properties.setProperty("databaseType", "mysql");
pageInterceptor.setProperties(property);
sqlSessionFactory.setPlugins(new Interceptor[]{sqlMonitorManager, pageInterceptor});
return sqlSessionFactory.getObject();
} private Resource[] getResource(String basePackage, String pattern) throws IOException {
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
+ ClassUtils.convertClassNameToResourcePath(new StandardEnvironment()
.resolveRequiredPlaceholders(basePackage)) + "/" + pattern;
Resource[] resources = new PathMatchingResourcePatternResolver().getResources(packageSearchPath);
return resources;
} /**
* 配置事务管理组件
* @return
*/
@Bean
public DataSourceTransactionManager transactionManager() {
logger.debug("start transactionManager");
return new DataSourceTransactionManager(dataSource());
}
}

mybatis-config.xml

 <?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="cacheEnabled" value="true"/>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="true"/>
<setting name="useGeneratedKeys" value="true"/>
<setting name="defaultExecutorType" value="SIMPLE"/>
<setting name="defaultStatementTimeout" value="10"/>
</settings>
</configuration>

PageInterceptor.java

 import com.xman.rainbow.car.common.Page;
import com.xman.rainbow.car.common.Pagination;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.statement.RoutingStatementHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.scripting.defaults.DefaultParameterHandler; import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import java.util.Properties; /**
* 分页拦截器,用于拦截需要进行分页查询的操作,然后对其进行分页处理。 利用拦截器实现Mybatis分页的原理:
* 要利用JDBC对数据库进行操作就必须要有一个对应的Statement对象,Mybatis在执行Sql语句前就会产生一个包含Sql语句的Statement对象,而且对应的Sql语句
* 是在Statement之前产生的,所以我们就可以在它生成Statement之前对用来生成Statement的Sql语句下手。在Mybatis中Statement语句是通过RoutingStatementHandler对象的
* prepare方法生成的。所以利用拦截器实现Mybatis分页的一个思路就是拦截StatementHandler接口的prepare方法,然后在拦截器方法中把Sql语句改成对应的分页查询Sql语句,之后再调用
* StatementHandler对象的prepare方法,即调用invocation.proceed()。
* 对于分页而言,在拦截器里面我们还需要做的一个操作就是统计满足当前条件的记录一共有多少,这是通过获取到了原始的Sql语句后,把它改为对应的统计语句再利用Mybatis封装好的参数和设
* 置参数的功能把Sql语句中的参数进行替换,之后再执行查询记录数的Sql语句进行总记录数的统计。
*
*/
@Intercepts({ @Signature(method = "prepare", type = StatementHandler.class, args = { Connection.class }) })
public class PageInterceptor implements Interceptor { private String databaseType;// 数据库类型,不同的数据库有不同的分页方法 /**
* 拦截后要执行的方法
*/
public Object intercept(Invocation invocation) throws Throwable {
// 对于StatementHandler其实只有两个实现类,一个是RoutingStatementHandler,另一个是抽象类BaseStatementHandler,
// BaseStatementHandler有三个子类,分别是SimpleStatementHandler,PreparedStatementHandler和CallableStatementHandler,
// SimpleStatementHandler是用于处理Statement的,PreparedStatementHandler是处理PreparedStatement的,而CallableStatementHandler是
// 处理CallableStatement的。Mybatis在进行Sql语句处理的时候都是建立的RoutingStatementHandler,而在RoutingStatementHandler里面拥有一个
// StatementHandler类型的delegate属性,RoutingStatementHandler会依据Statement的不同建立对应的BaseStatementHandler,即SimpleStatementHandler、
// PreparedStatementHandler或CallableStatementHandler,在RoutingStatementHandler里面所有StatementHandler接口方法的实现都是调用的delegate对应的方法。
// 我们在PageInterceptor类上已经用@Signature标记了该Interceptor只拦截StatementHandler接口的prepare方法,又因为Mybatis只有在建立RoutingStatementHandler的时候
// 是通过Interceptor的plugin方法进行包裹的,所以我们这里拦截到的目标对象肯定是RoutingStatementHandler对象。
RoutingStatementHandler handler = (RoutingStatementHandler) invocation.getTarget();
// 通过反射获取到当前RoutingStatementHandler对象的delegate属性
StatementHandler delegate = (StatementHandler) ReflectUtil.getFieldValue(handler, "delegate");
// 获取到当前StatementHandler的 boundSql,这里不管是调用handler.getBoundSql()还是直接调用delegate.getBoundSql()结果是一样的,因为之前已经说过了
// RoutingStatementHandler实现的所有StatementHandler接口方法里面都是调用的delegate对应的方法。
BoundSql boundSql = delegate.getBoundSql();
// 拿到当前绑定Sql的参数对象,就是我们在调用对应的Mapper映射语句时所传入的参数对象
Object paramObj = boundSql.getParameterObject(); // 判断参数里是否有page对象
Pagination page = null;
if (paramObj instanceof Pagination) {
page = (Pagination) paramObj;
} else if (paramObj instanceof Map) {
for (Object arg : ((Map) paramObj).values()) {
if (arg instanceof Page<?>) {
page = (Pagination) arg;
break;
}
}
} // 这里我们简单的通过传入的参数含有Pagination对象就认定它是需要进行分页操作的。
if (page != null) {
// 通过反射获取delegate父类BaseStatementHandler的mappedStatement属性
MappedStatement mappedStatement = (MappedStatement) ReflectUtil.getFieldValue(delegate, "mappedStatement");
// 拦截到的prepare方法参数是一个Connection对象
Connection connection = (Connection) invocation.getArgs()[0];
// 获取当前要执行的Sql语句,也就是我们直接在Mapper映射语句中写的Sql语句
String sql = boundSql.getSql();
// 给当前的page参数对象设置总记录数
if (page.getTotalCount() < 0) { // 如果总数为负数表需要设置
this.setTotalRecord(paramObj, mappedStatement, connection, page);
}
// 获取分页Sql语句
String pageSql = this.getPageSql(page, sql);
// 利用反射设置当前BoundSql对应的sql属性为我们建立好的分页Sql语句
ReflectUtil.setFieldValue(boundSql, "sql", pageSql);
}
return invocation.proceed();
} /**
* 拦截器对应的封装原始对象的方法
*/
public Object plugin(Object target) {
return Plugin.wrap(target, this);
} /**
* 设置注册拦截器时设定的属性
*/
public void setProperties(Properties properties) {
this.databaseType = properties.getProperty("databaseType");
} /**
* 根据page对象获取对应的分页查询Sql语句,这里只做了两种数据库类型,Mysql和Oracle 其它的数据库都 没有进行分页
*
* @param page 分页对象
* @param sql 原sql语句
* @return
*/
private String getPageSql(Pagination page, String sql) {
StringBuffer sqlBuffer = new StringBuffer(sql);
if ("mysql".equalsIgnoreCase(databaseType)) {
return getMysqlPageSql(page, sqlBuffer);
} else if ("oracle".equalsIgnoreCase(databaseType)) {
return getOraclePageSql(page, sqlBuffer);
}
return getMysqlPageSql(page, sqlBuffer);
} /**
* 获取Mysql数据库的分页查询语句
*
* @param page 分页对象
* @param sqlBuffer 包含原sql语句的StringBuffer对象
* @return Mysql数据库分页语句
*/
private String getMysqlPageSql(Pagination page, StringBuffer sqlBuffer) {
// 计算第一条记录的位置,Mysql中记录的位置是从0开始的。
int offset = (page.getPageNo() - 1) * page.getPageCount();
sqlBuffer.append(" limit ").append(offset).append(",").append(page.getPageCount());
return sqlBuffer.toString();
} /**
* 获取Oracle数据库的分页查询语句
*
* @param page 分页对象
* @param sqlBuffer 包含原sql语句的StringBuffer对象
* @return Oracle数据库的分页查询语句
*/
private String getOraclePageSql(Pagination page, StringBuffer sqlBuffer) {
// 计算第一条记录的位置,Oracle分页是通过rownum进行的,而rownum是从1开始的
int offset = (page.getPageNo() - 1) * page.getPageCount() + 1;
sqlBuffer.insert(0, "select u.*, rownum _rownum from (").append(") u where rownum < ")
.append(offset + page.getPageCount());
sqlBuffer.insert(0, "select * from (").append(") where _rownum >= ").append(offset);
// 上面的Sql语句拼接之后大概是这个样子:
// select * from (select u.*, rownum r from (select * from t_user) u where rownum < 31) where r >= 16
return sqlBuffer.toString();
} /**
* 给当前的参数对象page设置总记录数
*
* @param obj Mapper映射语句对应的参数对象
* @param mappedStatement Mapper映射语句
* @param connection 当前的数据库连接
*/
private void setTotalRecord(Object obj, MappedStatement mappedStatement, Connection connection, Pagination page) {
// 获取对应的BoundSql,这个BoundSql其实跟我们利用StatementHandler获取到的BoundSql是同一个对象。
// delegate里面的boundSql也是通过mappedStatement.getBoundSql(paramObj)方法获取到的。
BoundSql boundSql = mappedStatement.getBoundSql(obj);
// 获取到我们自己写在Mapper映射语句中对应的Sql语句
String sql = boundSql.getSql();
// 通过查询Sql语句获取到对应的计算总记录数的sql语句
String countSql = this.getCountSql(sql);
// 通过BoundSql获取对应的参数映射
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
// 利用Configuration、查询记录数的Sql语句countSql、参数映射关系parameterMappings和参数对象page建立查询记录数对应的BoundSql对象。
BoundSql countBoundSql = new BoundSql(mappedStatement.getConfiguration(), countSql, parameterMappings, obj);
// 在原boundSQL中存在additionalParameters等参数,new出来的sql可能没有这些参数,会造成生成sql是报错,所以设置进来
// 还有一种方法即就用原来的BoundSql, 改掉里面的sql, 用完后再改回来即可
ReflectUtil.setFieldValue(countBoundSql, "additionalParameters", ReflectUtil.getFieldValue(boundSql, "additionalParameters"));
ReflectUtil.setFieldValue(countBoundSql, "metaParameters", ReflectUtil.getFieldValue(boundSql, "metaParameters")); // 通过mappedStatement、参数对象page和BoundSql对象countBoundSql建立一个用于设定参数的ParameterHandler对象
ParameterHandler parameterHandler = new DefaultParameterHandler(mappedStatement, obj, countBoundSql);
// 通过connection建立一个countSql对应的PreparedStatement对象。
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
pstmt = connection.prepareStatement(countSql);
// 通过parameterHandler给PreparedStatement对象设置参数
parameterHandler.setParameters(pstmt);
// 之后就是执行获取总记录数的Sql语句和获取结果了。
rs = pstmt.executeQuery();
if (rs.next()) {
int totalRecord = rs.getInt(1);
// 给当前的参数page对象设置总记录数
page.setTotalCount(totalRecord);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (rs != null)
rs.close();
if (pstmt != null)
pstmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
} /**
* 根据原Sql语句获取对应的查询总记录数的Sql语句
*
* @param sql
* @return
*/
private String getCountSql(String sql) {
return "select count(1) from (" + sql + ") _tmp";
} /**
* 利用反射进行操作的一个工具类
*
*/
private static class ReflectUtil {
/**
* 利用反射获取指定对象的指定属性
*
* @param obj 目标对象
* @param fieldName 目标属性
* @return 目标属性的值
*/
public static Object getFieldValue(Object obj, String fieldName) {
Object result = null;
Field field = ReflectUtil.getField(obj, fieldName);
if (field != null) {
field.setAccessible(true);
try {
result = field.get(obj);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return result;
} /**
* 利用反射获取指定对象里面的指定属性
*
* @param obj 目标对象
* @param fieldName 目标属性
* @return 目标字段
*/
private static Field getField(Object obj, String fieldName) {
Field field = null;
for (Class<?> clazz = obj.getClass(); clazz != Object.class; clazz = clazz.getSuperclass()) {
try {
field = clazz.getDeclaredField(fieldName);
break;
} catch (NoSuchFieldException e) {
// 这里不用做处理,子类没有该字段可能对应的父类有,都没有就返回null。
}
}
return field;
} /**
* 利用反射设置指定对象的指定属性为指定的值
*
* @param obj 目标对象
* @param fieldName 目标属性
* @param fieldValue 目标值
*/
/* public static void setFieldValue(Object obj, String fieldName, String fieldValue) {
Field field = ReflectUtil.getField(obj, fieldName);
if (field != null) {
try {
field.setAccessible(true);
field.set(obj, fieldValue);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}*/
/**
* 利用反射设置指定对象的指定属性为指定的值
*
* @param obj 目标对象
* @param fieldName 目标属性
* @param fieldValue 目标值
*/
public static void setFieldValue(Object obj, String fieldName, Object fieldValue) {
Field field = ReflectUtil.getField(obj, fieldName);
if (field != null) {
try {
field.setAccessible(true);
field.set(obj, fieldValue);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
} }

application.properties文件

 #### 测试环境

 # datasource
# 驱动配置信息
datasource.driverClass=com.mysql.jdbc.Driver
datasource.username=root
datasource.password=123456
datasource.jdbcUrl=localhost
#连接池的配置信息
datasource.maxIdle=20
datasource.minIdle=1
datasource.maxWait=60000
datasource.validationQuery=: /* ping */ select 1
datasource.maxActive=3
datasource.testBorrow=false
datasource.testOnReturn=false
datasource.testWhileIdle=true
datasource.timeBetweenEvictionRunsMills=60000
datasource.minEvictableIdleTimeMillis=60000

java文件配置MySQL的更多相关文章

  1. java文件来演示如何访问MySQL数据库

    java文件来演示如何访问MySQL数据库. 注:在命令行或用一个SQL的前端软件创建Database. 先创建数据库: CREATE DATABASE SCUTCS; 接着,创建表: CREATE ...

  2. java+tomcat+Eclipse+mysql配置

    Java下载及配置: 1. 下载:http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html ...

  3. Linux配置mysql (centos配置java环境 mysql配置篇 总结四)

    ♣安装的几种方法和比较 ♣配置yum源 ♣安装mysql ♣启动mysql ♣修改密码 ♣导入.sql文件 ♣缓存设置 ♣允许远程登录(navicat) ♣配置编码为utf8  1.关于Linux系统 ...

  4. eclipse中web项目部署以后jsp的java文件找不到问题(Tomcat配置serverlocations)

    我的开发环境:eclipse kepler (4.3)+tomcat7.0.42. 在我想看eclipse中web项目jsp文件被tomcat转换成java以后的java源文件的位置,发现正常情况下的 ...

  5. 在my.ini文件中配置mysql统一字符集

    测试的mysql版本为:5.7.14 查看mysql字符集命令: show variables like 'character_set_%'; 以下是在my.ini文件中配置mysql统一字符集参数: ...

  6. MySQL慢查询日志相关的文件配置和使用。

    MySQL慢查询日志提供了超过指定时间阈值的查询信息,为性能优化提供了主要的参考依据,是一个非常实用的功能,MySQL慢查询日志的开启和配置非常简单,可以指定记录的文件(或者表),超过的时间阈值等就可 ...

  7. Django项目的创建与介绍.应用的创建与介绍.启动项目.pycharm创建启动项目.生命周期.三件套.静态文件.请求及数据.配置Mysql完成数据迁移.单表ORM记录的增删改查

    一.Django项目的创建与介绍 ''' 安装Django #在cmd中输入pip3 #出现这个错误Fatal error in launcher: Unable to create process ...

  8. mysql之存储引擎和文件配置

    (查看系统服务,在运行里输入services.msc) 补充:将mysql做成系统服务:mysqld --install 取消:mysqld --romove 在服务中可以直接鼠标操作mysql服务的 ...

  9. centos MySQL主从配置 ntsysv chkconfig setup命令 配置MySQL 主从 子shell MySQL备份 kill命令 pid文件 discuz!论坛数据库读写分离 双主搭建 mysql.history 第二十九节课

    centos  MySQL主从配置 ntsysv   chkconfig  setup命令  配置MySQL 主从 子shell  MySQL备份  kill命令  pid文件  discuz!论坛数 ...

随机推荐

  1. python paramiko模块学习分享

    python paramiko模块学习分享 paramiko是用python语言写的一个模块,遵循SSH2协议,支持以加密和认证的方式,进行远程服务器的连接.paramiko支持Linux, Sola ...

  2. jeecms jeecmsv93建库

    create tablespace jeecms93 datafile 'jeecms93.dbf' size 100M reuse autoextend on next 50M;1. 2.drop ...

  3. mac idea解决快捷键的问题

    取消mac的快捷键 设置->键盘->快捷键 我这里取消的有:聚焦->显示聚焦搜索 应用快捷键->显示帮助菜单. 类似eclipse的自动提示错误的解决方案(quick fix ...

  4. Oracle一条数据多表连插

    insert all into T_TRAIN_MARSHALLING <trim prefix="(GKEY," suffix=")" suffixOv ...

  5. JAVA工具包_BeanUtils

    简介 大多数的java开发者通常在创建Java类的时候都会遵循JavaBean的命名模式,对类的属性生成getters方法和setters方法.通过调用相应的getXxx和setXxx方法,直接访问这 ...

  6. Python Flask高级编程之从0到1开发《鱼书》精品项目 ✍✍✍

    Python Flask高级编程之从0到1开发<鱼书>精品项目  一 .安装环境我们使用 flask web框架,并用 sqlalchemy来做数据库映射,并使用 migrate做数据迁移 ...

  7. 小程序swiper-item内容过多显示不全的解决方案

    最近在项目遇到swiper高度不能自适应,导致swiper-item 里面的内容过多时只能显示一部分,最终解决方案:<swiper current="{{currentTab}}&qu ...

  8. 【默默努力】ig-wxz-and-hotdog

    这个是一个非常跟热点的小游戏,思聪吃热狗.这个游戏的话,我感觉思路还挺简单的,天上会掉热狗和障碍物, 思聪在下面张开嘴巴,进行左右移动,接热狗.如果吃到的是热狗就得一分,如果思聪吃到的不是热狗,是障碍 ...

  9. JavaScript中对象的3种定义方式

    对象是有特性(属性)和功能(方法)的集合体. 定义对象有以下3种方式: 1.使用系统的new Object()方式定义对象 2.使用对象字面量定义对象( 即使用{}语法糖结构定义对象 ) 3.使用自定 ...

  10. 制作windows10系统启动U盘,从零开始。

    1.打开百度,搜索windows下载,选个这个点击进去. 2.会看到下图,然后点击立即下载工具按钮. 3.接下来由于网络的原因,可能需要漫长的等待.会下载一个MediaCreationTool1903 ...