java文件配置MySQL
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的更多相关文章
- java文件来演示如何访问MySQL数据库
java文件来演示如何访问MySQL数据库. 注:在命令行或用一个SQL的前端软件创建Database. 先创建数据库: CREATE DATABASE SCUTCS; 接着,创建表: CREATE ...
- java+tomcat+Eclipse+mysql配置
Java下载及配置: 1. 下载:http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html ...
- Linux配置mysql (centos配置java环境 mysql配置篇 总结四)
♣安装的几种方法和比较 ♣配置yum源 ♣安装mysql ♣启动mysql ♣修改密码 ♣导入.sql文件 ♣缓存设置 ♣允许远程登录(navicat) ♣配置编码为utf8 1.关于Linux系统 ...
- eclipse中web项目部署以后jsp的java文件找不到问题(Tomcat配置serverlocations)
我的开发环境:eclipse kepler (4.3)+tomcat7.0.42. 在我想看eclipse中web项目jsp文件被tomcat转换成java以后的java源文件的位置,发现正常情况下的 ...
- 在my.ini文件中配置mysql统一字符集
测试的mysql版本为:5.7.14 查看mysql字符集命令: show variables like 'character_set_%'; 以下是在my.ini文件中配置mysql统一字符集参数: ...
- MySQL慢查询日志相关的文件配置和使用。
MySQL慢查询日志提供了超过指定时间阈值的查询信息,为性能优化提供了主要的参考依据,是一个非常实用的功能,MySQL慢查询日志的开启和配置非常简单,可以指定记录的文件(或者表),超过的时间阈值等就可 ...
- Django项目的创建与介绍.应用的创建与介绍.启动项目.pycharm创建启动项目.生命周期.三件套.静态文件.请求及数据.配置Mysql完成数据迁移.单表ORM记录的增删改查
一.Django项目的创建与介绍 ''' 安装Django #在cmd中输入pip3 #出现这个错误Fatal error in launcher: Unable to create process ...
- mysql之存储引擎和文件配置
(查看系统服务,在运行里输入services.msc) 补充:将mysql做成系统服务:mysqld --install 取消:mysqld --romove 在服务中可以直接鼠标操作mysql服务的 ...
- centos MySQL主从配置 ntsysv chkconfig setup命令 配置MySQL 主从 子shell MySQL备份 kill命令 pid文件 discuz!论坛数据库读写分离 双主搭建 mysql.history 第二十九节课
centos MySQL主从配置 ntsysv chkconfig setup命令 配置MySQL 主从 子shell MySQL备份 kill命令 pid文件 discuz!论坛数 ...
随机推荐
- Systm.IO.File.cs
ylbtech-Systm.IO.File.cs 1.程序集 mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c5619 ...
- day25-静态、组合、继承
#!/usr/bin/env python # -*- coding:utf-8 -*- # ----------------------------------------------------- ...
- reboot与shutdown -r now 区别与联系(又收集了init和halt的小知识)
在linux命令中reboot是重新启动,shutdown -r now是立即停止然后重新启动,都说他们两个是一样的,其实是有一定的区别的. shutdown命令可以安全地关闭或重启Linux系统,它 ...
- Java 10的10个新特性,将彻底改变你写代码的方式!
Java 9才发布几个月,很多玩意都没整明白,现在Java 10又快要来了.. 这时候我真尼玛想说:线上用的JDK 7 甚至JDK 6,JDK 8 还没用熟,JDK 9 才发布不久不知道啥玩意,JDK ...
- 多重背包 /// 单调队列DP oj1943
题目大意: em.... 就是多重背包 挑战340页的东西 ...自己的笔记总结总是比较乱的 重点:原始的状态转移方程中 更新第 i 种物品时 重量%w[i] 的值不同 则它们之间是相互独立的: 1- ...
- Resource Archiver HDU - 3247 AC自动机+BFS+状压
题意: 给出n个资源串,m个病毒串,现在要如何连接资源串使得不含病毒串(可以重叠,样例就是重叠的). 题解: 这题的套路和之前的很不同了,之前的AC自动机+DP的题目一般都是通过teir图去转移, 这 ...
- 二分图——poj2239
水题 /* n门课,每门课有一个时间t 要求最大的n->t的匹配 */ #include<iostream> #include<cstring> #include< ...
- Codeforces Round #599 (Div. 2)的简单题题解
难题不会啊…… 我感觉写这个的原因就是因为……无聊要给大家翻译题面 A. Maximum Square 简单题意: 有$n$条长为$a_i$,宽为1的木板,现在你可以随便抽几个拼在一起,然后你要从这一 ...
- 深入浅出 Java Concurrency (37): 并发总结 part 1 死锁与活跃度[转]
死锁与活跃度 前面谈了很多并发的特性和工具,但是大部分都是和锁有关的.我们使用锁来保证线程安全,但是这也会引起一些问题. 锁顺序死锁(lock-ordering deadlock):多个线程试图通 ...
- Windows进程创建的流程分析
. 创建进程的大体流程: 创建进程的过程就是构建一个环境,这个环境包含了很多的机制 (比如自我保护, 与外界通信等等). 构建这个环境需要两种"人"来协调完成(用户态和内核 ...