java配置mysql路径_java文件配置MySQL

1 importcom.xman.rainbow.car.common.Page;2 importcom.xman.rainbow.car.common.Pagination;3 importorg.apache.ibatis.executor.parameter.ParameterHandler;4 importorg.apache.ibatis.executor.statement.RoutingStatementHandler;5 importorg.apache.ibatis.executor.statement.StatementHandler;6 importorg.apache.ibatis.mapping.BoundSql;7 importorg.apache.ibatis.mapping.MappedStatement;8 importorg.apache.ibatis.mapping.ParameterMapping;9 import org.apache.ibatis.plugin.*;10 importorg.apache.ibatis.scripting.defaults.DefaultParameterHandler;11

12 importjava.lang.reflect.Field;13 importjava.sql.Connection;14 importjava.sql.PreparedStatement;15 importjava.sql.ResultSet;16 importjava.sql.SQLException;17 importjava.util.List;18 importjava.util.Map;19 importjava.util.Properties;20

21 /**

22 * 分页拦截器,用于拦截需要进行分页查询的操作,然后对其进行分页处理。 利用拦截器实现Mybatis分页的原理:23 * 要利用JDBC对数据库进行操作就必须要有一个对应的Statement对象,Mybatis在执行Sql语句前就会产生一个包含Sql语句的Statement对象,而且对应的Sql语句24 * 是在Statement之前产生的,所以我们就可以在它生成Statement之前对用来生成Statement的Sql语句下手。在Mybatis中Statement语句是通过RoutingStatementHandler对象的25 * prepare方法生成的。所以利用拦截器实现Mybatis分页的一个思路就是拦截StatementHandler接口的prepare方法,然后在拦截器方法中把Sql语句改成对应的分页查询Sql语句,之后再调用26 * StatementHandler对象的prepare方法,即调用invocation.proceed()。27 * 对于分页而言,在拦截器里面我们还需要做的一个操作就是统计满足当前条件的记录一共有多少,这是通过获取到了原始的Sql语句后,把它改为对应的统计语句再利用Mybatis封装好的参数和设28 * 置参数的功能把Sql语句中的参数进行替换,之后再执行查询记录数的Sql语句进行总记录数的统计。29 *30 */

31 @Intercepts({ @Signature(method = "prepare", type = StatementHandler.class, args = { Connection.class}) })32 public class PageInterceptor implementsInterceptor {33

34 private String databaseType;//数据库类型,不同的数据库有不同的分页方法

35

36 /**

37 * 拦截后要执行的方法38 */

39 public Object intercept(Invocation invocation) throwsThrowable {40 //对于StatementHandler其实只有两个实现类,一个是RoutingStatementHandler,另一个是抽象类BaseStatementHandler,41 //BaseStatementHandler有三个子类,分别是SimpleStatementHandler,PreparedStatementHandler和CallableStatementHandler,42 //SimpleStatementHandler是用于处理Statement的,PreparedStatementHandler是处理PreparedStatement的,而CallableStatementHandler是43 //处理CallableStatement的。Mybatis在进行Sql语句处理的时候都是建立的RoutingStatementHandler,而在RoutingStatementHandler里面拥有一个44 //StatementHandler类型的delegate属性,RoutingStatementHandler会依据Statement的不同建立对应的BaseStatementHandler,即SimpleStatementHandler、45 //PreparedStatementHandler或CallableStatementHandler,在RoutingStatementHandler里面所有StatementHandler接口方法的实现都是调用的delegate对应的方法。46 //我们在PageInterceptor类上已经用@Signature标记了该Interceptor只拦截StatementHandler接口的prepare方法,又因为Mybatis只有在建立RoutingStatementHandler的时候47 //是通过Interceptor的plugin方法进行包裹的,所以我们这里拦截到的目标对象肯定是RoutingStatementHandler对象。

48 RoutingStatementHandler handler =(RoutingStatementHandler) invocation.getTarget();49 //通过反射获取到当前RoutingStatementHandler对象的delegate属性

50 StatementHandler delegate = (StatementHandler) ReflectUtil.getFieldValue(handler, "delegate");51 //获取到当前StatementHandler的 boundSql,这里不管是调用handler.getBoundSql()还是直接调用delegate.getBoundSql()结果是一样的,因为之前已经说过了52 //RoutingStatementHandler实现的所有StatementHandler接口方法里面都是调用的delegate对应的方法。

53 BoundSql boundSql =delegate.getBoundSql();54 //拿到当前绑定Sql的参数对象,就是我们在调用对应的Mapper映射语句时所传入的参数对象

55 Object paramObj =boundSql.getParameterObject();56

57 //判断参数里是否有page对象

58 Pagination page = null;59 if (paramObj instanceofPagination) {60 page =(Pagination) paramObj;61 } else if (paramObj instanceofMap) {62 for(Object arg : ((Map) paramObj).values()) {63 if (arg instanceof Page>) {64 page =(Pagination) arg;65 break;66 }67 }68 }69

70 //这里我们简单的通过传入的参数含有Pagination对象就认定它是需要进行分页操作的。

71 if (page != null) {72 //通过反射获取delegate父类BaseStatementHandler的mappedStatement属性

73 MappedStatement mappedStatement = (MappedStatement) ReflectUtil.getFieldValue(delegate, "mappedStatement");74 //拦截到的prepare方法参数是一个Connection对象

75 Connection connection = (Connection) invocation.getArgs()[0];76 //获取当前要执行的Sql语句,也就是我们直接在Mapper映射语句中写的Sql语句

77 String sql =boundSql.getSql();78 //给当前的page参数对象设置总记录数

79 if (page.getTotalCount() < 0) { //如果总数为负数表需要设置

80 this.setTotalRecord(paramObj, mappedStatement, connection, page);81 }82 //获取分页Sql语句

83 String pageSql = this.getPageSql(page, sql);84 //利用反射设置当前BoundSql对应的sql属性为我们建立好的分页Sql语句

85 ReflectUtil.setFieldValue(boundSql, "sql", pageSql);86 }87 returninvocation.proceed();88 }89

90 /**

91 * 拦截器对应的封装原始对象的方法92 */

93 publicObject plugin(Object target) {94 return Plugin.wrap(target, this);95 }96

97 /**

98 * 设置注册拦截器时设定的属性99 */

100 public voidsetProperties(Properties properties) {101 this.databaseType = properties.getProperty("databaseType");102 }103

104 /**

105 * 根据page对象获取对应的分页查询Sql语句,这里只做了两种数据库类型,Mysql和Oracle 其它的数据库都 没有进行分页106 *107 *@parampage 分页对象108 *@paramsql 原sql语句109 *@return

110 */

111 privateString getPageSql(Pagination page, String sql) {112 StringBuffer sqlBuffer = newStringBuffer(sql);113 if ("mysql".equalsIgnoreCase(databaseType)) {114 returngetMysqlPageSql(page, sqlBuffer);115 } else if ("oracle".equalsIgnoreCase(databaseType)) {116 returngetOraclePageSql(page, sqlBuffer);117 }118 returngetMysqlPageSql(page, sqlBuffer);119 }120

121 /**

122 * 获取Mysql数据库的分页查询语句123 *124 *@parampage 分页对象125 *@paramsqlBuffer 包含原sql语句的StringBuffer对象126 *@returnMysql数据库分页语句127 */

128 privateString getMysqlPageSql(Pagination page, StringBuffer sqlBuffer) {129 //计算第一条记录的位置,Mysql中记录的位置是从0开始的。

130 int offset = (page.getPageNo() - 1) *page.getPageCount();131 sqlBuffer.append(" limit ").append(offset).append(",").append(page.getPageCount());132 returnsqlBuffer.toString();133 }134

135 /**

136 * 获取Oracle数据库的分页查询语句137 *138 *@parampage 分页对象139 *@paramsqlBuffer 包含原sql语句的StringBuffer对象140 *@returnOracle数据库的分页查询语句141 */

142 privateString getOraclePageSql(Pagination page, StringBuffer sqlBuffer) {143 //计算第一条记录的位置,Oracle分页是通过rownum进行的,而rownum是从1开始的

144 int offset = (page.getPageNo() - 1) * page.getPageCount() + 1;145 sqlBuffer.insert(0, "select u.*, rownum _rownum from (").append(") u where rownum < ")146 .append(offset +page.getPageCount());147 sqlBuffer.insert(0, "select * from (").append(") where _rownum >= ").append(offset);148 //上面的Sql语句拼接之后大概是这个样子:149 //select * from (select u.*, rownum r from (select * from t_user) u where rownum < 31) where r >= 16

150 returnsqlBuffer.toString();151 }152

153 /**

154 * 给当前的参数对象page设置总记录数155 *156 *@paramobj Mapper映射语句对应的参数对象157 *@parammappedStatement Mapper映射语句158 *@paramconnection 当前的数据库连接159 */

160 private voidsetTotalRecord(Object obj, MappedStatement mappedStatement, Connection connection, Pagination page) {161 //获取对应的BoundSql,这个BoundSql其实跟我们利用StatementHandler获取到的BoundSql是同一个对象。162 //delegate里面的boundSql也是通过mappedStatement.getBoundSql(paramObj)方法获取到的。

163 BoundSql boundSql =mappedStatement.getBoundSql(obj);164 //获取到我们自己写在Mapper映射语句中对应的Sql语句

165 String sql =boundSql.getSql();166 //通过查询Sql语句获取到对应的计算总记录数的sql语句

167 String countSql = this.getCountSql(sql);168 //通过BoundSql获取对应的参数映射

169 List parameterMappings =boundSql.getParameterMappings();170 //利用Configuration、查询记录数的Sql语句countSql、参数映射关系parameterMappings和参数对象page建立查询记录数对应的BoundSql对象。

171 BoundSql countBoundSql = newBoundSql(mappedStatement.getConfiguration(), countSql, parameterMappings, obj);172 //在原boundSQL中存在additionalParameters等参数,new出来的sql可能没有这些参数,会造成生成sql是报错,所以设置进来173 //还有一种方法即就用原来的BoundSql, 改掉里面的sql, 用完后再改回来即可

174 ReflectUtil.setFieldValue(countBoundSql, "additionalParameters", ReflectUtil.getFieldValue(boundSql, "additionalParameters"));175 ReflectUtil.setFieldValue(countBoundSql, "metaParameters", ReflectUtil.getFieldValue(boundSql, "metaParameters"));176

177 //通过mappedStatement、参数对象page和BoundSql对象countBoundSql建立一个用于设定参数的ParameterHandler对象

178 ParameterHandler parameterHandler = newDefaultParameterHandler(mappedStatement, obj, countBoundSql);179 //通过connection建立一个countSql对应的PreparedStatement对象。

180 PreparedStatement pstmt = null;181 ResultSet rs = null;182 try{183 pstmt =connection.prepareStatement(countSql);184 //通过parameterHandler给PreparedStatement对象设置参数

185 parameterHandler.setParameters(pstmt);186 //之后就是执行获取总记录数的Sql语句和获取结果了。

187 rs =pstmt.executeQuery();188 if(rs.next()) {189 int totalRecord = rs.getInt(1);190 //给当前的参数page对象设置总记录数

191 page.setTotalCount(totalRecord);192 }193 } catch(SQLException e) {194 e.printStackTrace();195 } finally{196 try{197 if (rs != null)198 rs.close();199 if (pstmt != null)200 pstmt.close();201 } catch(SQLException e) {202 e.printStackTrace();203 }204 }205 }206

207 /**

208 * 根据原Sql语句获取对应的查询总记录数的Sql语句209 *210 *@paramsql211 *@return

212 */

213 privateString getCountSql(String sql) {214 return "select count(1) from (" + sql + ") _tmp";215 }216

217 /**

218 * 利用反射进行操作的一个工具类219 *220 */

221 private static classReflectUtil {222 /**

223 * 利用反射获取指定对象的指定属性224 *225 *@paramobj 目标对象226 *@paramfieldName 目标属性227 *@return目标属性的值228 */

229 public staticObject getFieldValue(Object obj, String fieldName) {230 Object result = null;231 Field field =ReflectUtil.getField(obj, fieldName);232 if (field != null) {233 field.setAccessible(true);234 try{235 result =field.get(obj);236 } catch(IllegalArgumentException e) {237 //TODO Auto-generated catch block

238 e.printStackTrace();239 } catch(IllegalAccessException e) {240 //TODO Auto-generated catch block

241 e.printStackTrace();242 }243 }244 returnresult;245 }246

247 /**

248 * 利用反射获取指定对象里面的指定属性249 *250 *@paramobj 目标对象251 *@paramfieldName 目标属性252 *@return目标字段253 */

254 private staticField getField(Object obj, String fieldName) {255 Field field = null;256 for (Class> clazz = obj.getClass(); clazz != Object.class; clazz =clazz.getSuperclass()) {257 try{258 field =clazz.getDeclaredField(fieldName);259 break;260 } catch(NoSuchFieldException e) {261 //这里不用做处理,子类没有该字段可能对应的父类有,都没有就返回null。

262 }263 }264 returnfield;265 }266

267 /**

268 * 利用反射设置指定对象的指定属性为指定的值269 *270 *@paramobj 目标对象271 *@paramfieldName 目标属性272 *@paramfieldValue 目标值273 */

274 /*public static void setFieldValue(Object obj, String fieldName, String fieldValue) {275 Field field = ReflectUtil.getField(obj, fieldName);276 if (field != null) {277 try {278 field.setAccessible(true);279 field.set(obj, fieldValue);280 } catch (IllegalArgumentException e) {281 // TODO Auto-generated catch block282 e.printStackTrace();283 } catch (IllegalAccessException e) {284 // TODO Auto-generated catch block285 e.printStackTrace();286 }287 }288 }*/

289 /**

290 * 利用反射设置指定对象的指定属性为指定的值291 *292 *@paramobj 目标对象293 *@paramfieldName 目标属性294 *@paramfieldValue 目标值295 */

296 public static voidsetFieldValue(Object obj, String fieldName, Object fieldValue) {297 Field field =ReflectUtil.getField(obj, fieldName);298 if (field != null) {299 try{300 field.setAccessible(true);301 field.set(obj, fieldValue);302 } catch(IllegalArgumentException e) {303 //TODO Auto-generated catch block

304 e.printStackTrace();305 } catch(IllegalAccessException e) {306 //TODO Auto-generated catch block

307 e.printStackTrace();308 }309 }310 }311 }312

313 }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值