曾经发过一篇文章,大概写的就是阿海多么多么厉害,见到某位同事在Hibernate的基础上封装了一下,就以一己之力开发什么什么框架,最后写了个超大的一坨的事。
那么,后续篇来了。阿海不是自负之人,当之前的CRUD框架并没有达到理想的结果时,阿海转向了Mybatis封装。别问我为什么不是Hibernate。我本来就不喜欢Hibernate,即使在之前的一家公司一直被强制性的约束使用Hibernate时,也没有对Hibernate产生什么真正的好感,反而屡次发现了Hibernate的一些问题。
或许是因为版本太老了得缘故吧(都是2016年的新世纪了,还在用Hibernate2)总之,bug层出不穷,极不稳定,而且还因为版本过老的远古,一些依赖或者受影响的包也必须使用老版本,哎不管怎么说,在那段逗逼的时光里敲着逗逼的代码,做着逗逼的事情。重复着逗逼的生活。所以,说到封装,我第一时间想到了mybatis。版本嘛,不高不低,就用我最熟练的3.2版本。至于我为什么不用更高的版本,主要是我第一次做系统的封装,先用我最拿手的试试,尽管说是最拿手的,但也好长时间没有玩儿过了,苦逼的玩儿了一年的hibernate2对于阿海的性格来说,简直就是煎熬。
扯了那么多没用的,接下来说说我这个Hibernate呃,打错了,是我这个MyBatis封装和之前的那个Hibernate封装有什么区别和优势。首先,最大的区别就是,Mybatis少不了xml文件。因为这是Mybatis的本质,也是他的精华所在。另外呢,就是没有防注入功能。占位付功能,在我封装后的Mybaits中,彻底废掉了。也不能说是彻底废掉,只是那些公用方法中的占位付给废掉了。当然,解决SQL注入并不一定非得让框架去支持,自己也可以写,随便写个参数拦截器就好了,当然也必须要写,不仅仅是为了解决SQL注入,比如html标记转义、敏感字符过滤直来的都是要有的吧?所以说,废掉通用方法中的占位付功能并不是一个不明智的选择。
接下来就是与Hibernate之间的缓存效率对比,准确的说是与那个封装之后的Hibernate的缓存对比。Hibernate的(缓存+事物)问题相信一些精通的朋友应该知道,当然,即使有一些知道的我还是要简单的说一下,毕竟一些朋友还是不知道的。。
在这段文字中,我觉得我应该严肃一下,不再逗逼。好了,且听我说:所谓缓存机制,Hibernate中的二级缓存利用了一个叫做“快照”的逗逼机制,本体来说的确挺厉害,然而碰到事物,就…就….这就尴尬了-_-!。为什么这么说呢?我先来介绍一下Hibernate的快照原理。当hibernate查询时,会给这个语句的结果生成一个缓存和快照,当再次查询时,他会从缓存中找到要查询的对象,然后与快照中的对比,当缓存和快照中的id(Hibernate给他定义的对象ID,叫OID,对象更新后OID会变)一致时,将不会从数据库中再次查询。而是直接使用缓存中的对象。这样,减少了sql语句的查询。对效率有一定的优化。那么问题来了,当开启事务时,每执行一次操作,缓存都会更新一次,而快照则是在提交之后才会更新。那么问题来了,当执行完一些sql时,缓存更新,这时候如果遭到回滚的话,快照则不会更新。那么这个更新后的缓存就是一个废弃的缓存,就是一个脏数据。如果正好用户没有配置快照的话,再次查询出来的数据则不会和数据库中的数据同步。所以就产生了错误数据。
那位同事或许也是意识到了这一点儿,然而他却直接关闭了缓存机制,唉、、、阿海心寒啊。遇到问题解决问题是阿海一贯的作风,然而遇到问题逃避问题则是阿海极为鄙视的。说到上面Mybatis废了占位付其实也并不是逃避,因为阿海用其他方式比如过滤器解决了。扯开这些不谈,基于Mybaits做的这个封装则是完美解决了这个问题,或者更准确的说,是根本就没有这个问题。这个问题仅存在于hibernate中。
去其他的就不用说了吧?这套基于Mybatis的封装保留了Mybatis的精髓,你依然可以配置mapper,编写xml,使用动态SQL,充分的发挥软编码的特性。
是上面吹了这么多,接下来应该说一下这个封装的结构了。其实也没有什么结构可言,因为之前写过那个不算完美的CRUD框架,所以很多东西都可以拿来服用,至少SQL生成这一块和注解这一块基本上可以复制粘贴。
通用XML:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.aiyi.core.dao.Dao">
<!-- 局部新增 -->
<insert id="addLocal">
${value}
</insert>
<!-- 整体新增 -->
<insert id="add">
${value}
</insert>
<!-- 根据ID查询单个 -->
<select id="getById" resultType="hashmap">
${value}
</select>
<!-- 根据ID查询单个字段 -->
<select id="getFieldById" resultType="hashmap">
${value}
</select>
<!-- 根据条件查询单个 -->
<select id="getByParm" resultType="hashmap">
${value}
</select>
<!-- 根据条件查询单个字段 -->
<select id="getFieldByParm" resultType="hashmap">
${value}
</select>
<!-- 条件查询列表 -->
<select id="selectList" resultType="hashmap">
${value}
</select>
<!-- 条件查询字段列表 -->
<select id="selectListField" resultType="hashmap">
${value}
</select>
<!-- 更新局部 -->
<update id="updateLocal">${value}</update>
<!-- 更新全部 -->
<update id="update">${value}</update>
<!-- 条件更新局部 -->
<update id="updateLocalByPram">${value}</update>
<!-- 条件更新全部 -->
<update id="updateByPram">${value}</update>
<!-- 根据ID删除 -->
<delete id="deleteById">
${value}
</delete>
<!-- 批量删除 -->
<delete id="deleteByparm">
${value}
</delete>
<!-- 自定义语句查询 -->
<select id="selectBySql" resultType="hashmap">
${value}
</select>
<!-- 自定义语句执行 -->
<update id="excuse">${value}</update>
<!-- 查询符合条件的数量 -->
<select id="selectCountByParm" resultType="Long">
${value}
</select>
<!-- 查询总数量 -->
<select id="selectCount" resultType="Long">
${value}
</select>
<!-- 内查询 -->
<select id="selectIn" resultType="hashmap">
${value}
</select>
<!-- 获取下一个序列的值 -->
<select id="fetchSeqNextval" resultType="Long" flushCache="true">
${value}
</select>
</mapper>
从这个mapper文件中可以看出为什么没有占位符了吧?
接下来就是通用dao
package com.aiyi.core.dao;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import com.aiyi.core.beans.Po;
import com.aiyi.core.beans.WherePrams;
/**
* 公共数据库操作层
* @author 郭胜凯
* @time 2016年5月3日下午2:55:13
* @email [email protected]
* @param <T> 实体PO类型
* @param <PK> PO主键类型
*/
public interface Dao<T extends Po, PK extends Serializable> {
/**
* 添加不为空的记录(只将不为空字段入库,效率高)
* @param po
* @return 受改变的记录数
*/
public int addLocal(T po);
/**
* 记录添加(所有字段入库,效率中)
* @param po
* @return
*/
public int add(T po);
/**
* 通过主键获取某个记录
* @param id 主键
* @return PO
*/
public T get(PK id);
/**
* 通过主键获取某个字段的值
* @param id
* @param fileName
* @return
*/
public Serializable getField(PK id, String fileName);
/**
* 条件获取一条记录
* @param t
* @param 条件表达式
* @return PO
*/
public T get(WherePrams where);
/**
* 条件获取某个记录字段
* @param where
* @param fileName
* @return
*/
public Serializable getFile(WherePrams where, String fileName);
/**
* 条件查询列表
* @param where 条件表达式
* @return PO列表
*/
public List<T> list(WherePrams where);
/**
* 查询某个字段列表
* @param where 条件表达式
* @param fileName 要查询的字段
* @return
*/
public Serializable[] listFile(WherePrams where, String fileName);
/**
* 查询某些字段
* @param where 条件表达式
* @param files 要查询的字段集
* @return 查询的PO字段列表
*/
public List<Map<String, Serializable>> listFiles(WherePrams where, String[] files);
/**
* 更新不为null的PO字段
* @param po
* @return 受影响的行数
*/
public int updateLocal(T po);
/**
* 更新PO的所有字段
* @param po
* @return 受影响的行数
*/
public int update(T po);
/**
* 条件更新不为null的字段
* @param po
* @param 条件表达式
* @return 受影响的行数
*/
public int updateLocal(T po, WherePrams where);
/**
* 条件更新所有字段
* @param po
* @param 条件表达式
* @return 受影响的行数
*/
public int update(T po, WherePrams where);
/**
* 删除某个记录
* @param id 主键
* @return 受影响的行数
*/
public int del(PK id);
/**
* 条件删除某个记录
* @param where 条件表达式
* @return 受影响的行数
*/
public int del(WherePrams where);
/**
* 自定义sql查询
* @param po 用于封装返回结果的Bean
* @param sql 用于执行查询的Sql
* @param args Sql占位付对应的参数
* @return 结果集合
*/
public List<Map<String, Object>> listBySql(String sql);
/**
* 执行自定义sql
* @param sql 用于执行的Sql
* @param args Sql占位付对应的参数
* @return 受影响的行数
*/
public int excuse(String sql);
/**
* 获取指定条件的记录数
* @param where 条件表达式
* @return 查询到的记录数
*/
public long count(WherePrams where);
/**
* 获取对应表中的记录数
* @return 表中的条数
*/
public long size();
/**
* 是否存在字段相同的记录(ID以及不为空的字段除外)
* @param po 参照实体
* @return
*/
public boolean isExist(T po);
/**
* 是否存在指定条件的记录
* @param where 条件表达式
* @return
*/
public boolean isExist(WherePrams where);
/**
* 内查询
* @param fileName 用于内查询的字段
* @param values 字段的值
* @return 查询到的结果集
*/
public List<T> in(String fileName, Serializable[] values);
/**
* 获得下一个序列的值
* @return
*/
public long nextId();
}
以及DAO的实现类
package com.aiyi.core.dao.impl;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.net.ConnectException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import org.mybatis.spring.SqlSessionTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Repository;
import com.aiyi.core.annotation.po.FieldName;
import com.aiyi.core.beans.Method;
import com.aiyi.core.beans.Po;
import com.aiyi.core.beans.Pram;
import com.aiyi.core.beans.WherePrams;
import com.aiyi.core.dao.Dao;
import com.aiyi.core.sql.where.C;
import com.aiyi.core.sql.where.SqlUtil;
import com.aiyi.core.util.GenericsUtils;
@SuppressWarnings("unused")
@Repository
public class DaoImpl<T extends Po, PK extends Serializable> implements Dao<T, PK> {
protected Logger logger = LoggerFactory.getLogger(this.getClass());
@Resource(name = "sqlSessionTemplateASS")
private SqlSessionTemplate sqlSessionTemplateASS;
private Class<T> entityClass;
private String pkName; //主键字段
private String idName; //对应id名称
private String seq; //当前主键
private String tableName;
private List<Pram> sqlParms;
private List<Pram> selectSqlParms;
private SqlUtil<T> sqlUtil;
@SuppressWarnings("unchecked")
public DaoImpl(){
super();
this.sqlUtil = new SqlUtil<T>();
this.entityClass = (Class<T>) GenericsUtils.getSuperClassGenricType(this.getClass());
this.sqlParms = this.sqlUtil.getPramList(this.entityClass);
this.selectSqlParms = this.sqlUtil.getPramListOfSelect(this.entityClass);
this.tableName = this.sqlUtil.getTableName(this.entityClass);
//习惯统一用‘id’做约束了,所以这里我给固定死了,不想固定的话可以修改这里
this.pkName = "id";
this.idName = "id";
this.seq = "id";
}
@Override
public int addLocal(T po) {
// TODO Auto-generated method stub
String sql = "insert into " + tableName + " (";
String prams = "";
String values = "";
List<Pram> pramList = SqlUtil.getPramListofStatic(po);
int index = 0;
for (int i = 0; i < pramList.size(); i++) {
if (pramList.get(i).getValue() == null || (pramList.get(i).getValue() + "") .equals("0")) {
continue;
}else{
if(index > 0){
prams += ",";
values += ",";
}
prams += pramList.get(i).getFile();
Object value = pramList.get(i).getValue();
if (value instanceof byte[] ) {
values += "‘" + new String((byte[]) value) + "‘";
}else if(value instanceof String){
values += "‘" + value + "‘";
}else{
values += value ;
}
index ++;
}
}
sql += prams + ") value (" + values +");";
SqlUtil.setFileValue(po, "id", nextId());
logger.debug(sql);
return sqlSessionTemplateASS.insert("addLocal", sql);
}
@Override
public int add(T po) {
// TODO Auto-generated method stub
String sql = "insert into " + tableName + " (";
String prams = "";
String values = "";
List<Pram> pramList = SqlUtil.getPramListofStatic(po);
for (int i = 0; i < pramList.size(); i++) {
prams += pramList.get(i).getFile();
if (pramList.get(i).getValue() == null) {
values += "null";
}else{
values += "‘" + pramList.get(i).getValue() + "‘";
}
if(i < pramList.size() -1){
prams += ",";
values += ",";
}
}
sql += prams + ") value (" + values +");";
SqlUtil.setFileValue(po, "id", nextId());
return sqlSessionTemplateASS.insert("add", sql);
}
@Override
public T get(PK id) {
// TODO Auto-generated method stub
String sql = "select ";
for (int i = 0; i < selectSqlParms.size(); i++) {
sql += selectSqlParms.get(i).getFile();
if(i < selectSqlParms.size() -1){
sql += ",";
}else{
sql += " ";
}
}
sql += " from " + tableName + " where id=‘" + id + "‘;";
Map<String, Object> resultMap = sqlSessionTemplateASS.selectOne(
"getById", sql);
return handleResult(resultMap, this.entityClass);
}
@Override
public Serializable getField(PK id, String fileName) {
// TODO Auto-generated method stub
String field = fileName;
String tabField = "";
Field f = sqlUtil.getField(this.entityClass, fileName);
if (null == f) {
logger.error("查询字段失败(无法找到" + this.entityClass + "中的" + fileName + "字段)");
}
FieldName annotation = f.getAnnotation(FieldName.class);
if (null == annotation) {
tabField = sqlUtil.toTableString(fileName) + " as " + fileName;
}else{
tabField = annotation.name() + " as " + fileName;
}
String sql = "select ";
sql += tabField + " from " + tableName + " where id=‘" + id + "‘;";
Map<String, Object> resultMap = sqlSessionTemplateASS.selectOne(
"getFieldById", sql);
return (Serializable) resultMap.get(fileName);
}
@Override
public T get(WherePrams where) {
// TODO Auto-generated method stub
String sql = "select ";
for (int i = 0; i < selectSqlParms.size(); i++) {
sql += selectSqlParms.get(i).getFile();
if(i < selectSqlParms.size() -1){
sql += ",";
}else{
sql += " ";
}
}
sql += "from " + tableName + where.getWherePrams() + ";";
Map<String, Object> resultMap = sqlSessionTemplateASS.selectOne(
"getByParm", sql);
return handleResult(resultMap, this.entityClass);
}
@Override
public Serializable getFile(WherePrams where, String fileName) {
// TODO Auto-generated method stub
String field = fileName;
String tabField = "";
Field f = sqlUtil.getField(this.entityClass, fileName);
if (null == f) {
logger.error("查询字段失败(无法找到" + this.entityClass + "中的" + fileName + "字段)");
}
FieldName annotation = f.getAnnotation(FieldName.class);
if (null == annotation) {
tabField = sqlUtil.toTableString(fileName) + " as " + fileName;
}else{
tabField = annotation.name() + " as " + fileName;
}
String sql = "select ";
sql += tabField + " from " + tableName + where.getWherePrams() + ";";
Map<String, Object> resultMap = sqlSessionTemplateASS.selectOne(
"getFieldByParm", sql);
return (Serializable) resultMap.get(fileName);
}
@Override
public List<T> list(WherePrams where) {
// TODO Auto-generated method stub
String sql = "select ";
for (int i = 0; i < selectSqlParms.size(); i++) {
sql += selectSqlParms.get(i).getFile();
if(i < selectSqlParms.size() -1){
sql += ",";
}else{
sql += " ";
}
}
sql += "from " + tableName + where.getWherePrams() + ";";
List<Map<String, Object>> selectList = sqlSessionTemplateASS.selectList("selectList", sql);
List<T> list = new ArrayList<>();
for (Map<String, Object> map : selectList) {
T t = handleResult(map, this.entityClass);
list.add(t);
}
return list;
}
@Override
public Serializable[] listFile(WherePrams where, String fileName) {
// TODO Auto-generated method stub
String field = fileName;
String tabField = "";
Field f = sqlUtil.getField(this.entityClass, fileName);
if (null == f) {
logger.error("查询指定字段集失败(无法序列化" + this.entityClass + "中的" + fileName + "字段)");
}
FieldName annotation = f.getAnnotation(FieldName.class);
if (null == annotation) {
tabField = sqlUtil.toTableString(fileName) + " as " + fileName;
}else{
tabField = annotation.name() + " as " + fileName;
}
String sql = "select ";
sql += tabField + " from " + tableName + where.getWherePrams() + ";";
List<Map<String, Object>> resultMap = sqlSessionTemplateASS.selectList("selectListField", sql);
Serializable[] fields = new Serializable[resultMap.size()];
for (int i = 0; i < resultMap.size(); i++) {
if (null != resultMap.get(i)) {
fields[i] =(Serializable) resultMap.get(i).get(fileName);
}
}
return fields;
}
@Override
public List<Map<String, Serializable>> listFiles(WherePrams where, String[] files) {
// TODO Auto-generated method stub
String tabField = "";
int index = 1;
for (String field : files) {
Field f = sqlUtil.getField(this.entityClass, field);
if (null == f) {
logger.error("查询指定字段集失败(无法序列化" + this.entityClass + "中的" + field + "字段)");
}
FieldName annotation = f.getAnnotation(FieldName.class);
if (null == annotation) {
tabField += sqlUtil.toTableString(field) + " as " + field;
}else{
tabField += annotation.name() + " as " + field;
}
if (index < files.length) {
tabField += ",";
}
index ++;
}
String sql = "select ";
sql += tabField + " from " + tableName + where.getWherePrams() + ";";
List<Map<String, Serializable>> resultMap = sqlSessionTemplateASS.selectList("selectListField", sql);
return resultMap;
}
@Override
public int updateLocal(T po) {
// TODO Auto-generated method stub
Serializable id = sqlUtil.getFileValue(po, "id");
if(null == id){
return 0;
}
String sql = "update " + tableName + " set ";
List<Pram> prams = sqlUtil.getPramList(po);
for (int i = 0; i < prams.size(); i++) {
if(null != prams.get(i).getValue()){
sql += prams.get(i).getFile() + "=";
Object value = prams.get(i).getValue();
if (value instanceof byte[] ) {
sql += "‘" + new String((byte[]) value) + "‘";
}else if(value instanceof String){
sql += "‘" + value + "‘";
}else{
sql += value ;
}
// sql += prams.get(i).getFile() + "=‘" + prams.get(i).getValue() + "‘";
if (i < prams.size() -1) {
sql += ",";
}
}
}
sql += " where id=‘" + id +"‘;";
return sqlSessionTemplateASS.update("updateLocal", sql);
}
@Override
public int update(T po) {
// TODO Auto-generated method stub
Serializable id = sqlUtil.getFileValue(po, "id");
if(null == id){
return 0;
}
String sql = "update " + tableName + " set ";
List<Pram> prams = sqlUtil.getPramList(po);
for (int i = 0; i < prams.size(); i++) {
if(null != prams.get(i).getValue()){
sql += prams.get(i).getFile() + "=";
Object value = prams.get(i).getValue();
if (value instanceof byte[] ) {
sql += "‘" + new String((byte[]) value) + "‘";
}else if(value instanceof String){
sql += "‘" + value + "‘";
}else{
sql += value ;
}
// sql += prams.get(i).getFile() + "=‘" + prams.get(i).getValue() + "‘";
if (i < prams.size() -1) {
sql += ",";
}
}else{
sql += prams.get(i).getFile() + "=null";
if (i < prams.size() -1) {
sql += ",";
}
}
}
sql += " where id=‘" + id +"‘;";
return sqlSessionTemplateASS.update("update", sql);
}
@Override
public int updateLocal(T po, WherePrams where) {
// TODO Auto-generated method stub
String sql = "update " + tableName + " set ";
List<Pram> prams = sqlUtil.getPramList(po);
for (int i = 0; i < prams.size(); i++) {
if(null != prams.get(i).getValue()){
sql += prams.get(i).getFile() + "=";
Object value = prams.get(i).getValue();
if (value instanceof byte[] ) {
sql += "‘" + new String((byte[]) value) + "‘";
}else if(value instanceof String){
sql += "‘" + value + "‘";
}else{
sql += value ;
}
// sql += prams.get(i).getFile() + "=‘" + prams.get(i).getValue() + "‘";
if (i < prams.size() -1) {
sql += ",";
}
}
}
sql += where.getWherePrams() +"‘;";
return sqlSessionTemplateASS.update("updateLocalByPram", sql);
}
@Override
public int update(T po, WherePrams where) {
// TODO Auto-generated method stub
String sql = "update " + tableName + " set ";
Object[] o = new Object[sqlParms.size()];
for (int i = 0; i < sqlParms.size(); i++) {
if(null != sqlParms.get(i).getValue()){
sql += sqlParms.get(i).getFile() + "=" + sqlParms.get(i).getValue();
if (i < sqlParms.size() -1) {
sql += ",";
}
}else{
sql += sqlParms.get(i).getFile() + "=null";
if (i < sqlParms.size() -1) {
sql += ",";
}
}
}
sql += where.getWherePrams() + "‘;";
return sqlSessionTemplateASS.update("updateByPram", sql);
}
@Override
public int del(PK id) {
// TODO Auto-generated method stub
String sql = "delete from " + tableName + " where id=" + id;
return sqlSessionTemplateASS.delete("deleteById", sql);
}
@Override
public int del(WherePrams where) {
// TODO Auto-generated method stub
String sql = "delete from " + tableName + where.getWherePrams();
return sqlSessionTemplateASS.delete("deleteByparm", sql);
}
@Override
public List<Map<String, Object>> listBySql(String sql) {
// TODO Auto-generated method stub
List<Map<String, Object>> selectList = sqlSessionTemplateASS.selectList("selectBySql", sql);
return selectList;
}
@Override
public int excuse(String sql) {
// TODO Auto-generated method stub
return sqlSessionTemplateASS.update("excuse", sql);
}
@Override
public long count(WherePrams where) {
// TODO Auto-generated method stub
String sql = "select count(*) from ";
sql += tableName + where.getWherePrams();
long count = sqlSessionTemplateASS.selectOne("selectCountByParm", sql);
return count;
}
@Override
public long size() {
// TODO Auto-generated method stub
String sql = "select count(*) from " + tableName;
long count = sqlSessionTemplateASS.selectOne("selectCount", sql);
return count;
}
@Override
public boolean isExist(T po) {
// TODO Auto-generated method stub
WherePrams wherePrams = Method.createDefault();
List<Pram> list = SqlUtil.getPramListofStatic(po);
for (int i = 0; i < list.size(); i++) {
if (i == 0) {
wherePrams = Method.where(list.get(i).getFile(), C.EQ, (Serializable)list.get(i).getValue());
}else{
wherePrams.and(list.get(i).getFile(), C.EQ, (Serializable)list.get(i).getValue());
}
}
return count(wherePrams) > 0;
}
@Override
public boolean isExist(WherePrams where) {
// TODO Auto-generated method stub
return count(where) > 0;
}
@Override
public List<T> in(String fileName, Serializable[] values) {
// TODO Auto-generated method stub
String sql = "select ";
for (int i = 0; i < sqlParms.size(); i++) {
sql += selectSqlParms.get(i).getFile();
if(i < selectSqlParms.size() -1){
sql += ",";
}else{
sql += " ";
}
}
sql += "from " + tableName + " where " + fileName + " in ";
String value = "(";
for(int i = 0; i < values.length; i++){
if(i < values.length -1){
value += values[i] + ",";
}else{
value += values[i] + ");";
}
}
sql += value;
List<Map<String, Object>> selectList = sqlSessionTemplateASS.selectList("selectIn", sql);
List<T> list = new ArrayList<>();
for (Map<String, Object> map : selectList) {
T t = handleResult(map, this.entityClass);
list.add(t);
}
return list;
}
private T handleResult(Map<String, Object> resultMap, Class<T> tClazz) {
if (null == resultMap) {
return null;
}
T t = null;
try {
t = tClazz.newInstance();
} catch (InstantiationException e) {
logger.error("/********************************");
logger.error("实例化Bean失败(" + this.entityClass + ")!"
+ e.getMessage());
logger.error("/********************************");
} catch (IllegalAccessException e) {
logger.error("/********************************");
logger.error("实例化Bean失败(" + this.entityClass + ")!"
+ e.getMessage());
logger.error("/********************************");
}
for (Map.Entry<String, Object> entry : resultMap.entrySet()) {
String key = entry.getKey();
Serializable val = (Serializable) entry.getValue();
try {
SqlUtil.setFileValue(t, key, val);
} catch (Exception e) {
// TODO: handle exception
logger.error("/********************************");
logger.error("/实例化Bean失败(" + this.entityClass + ")不能赋值到字段(" + key + "):"
+ e.getMessage());
logger.error("/********************************");
}
}
return t;
}
/**
* 获取某表的下一个Id
*/
public long nextId(){
String sql = "SELECT auto_increment FROM information_schema.`TABLES` WHERE TABLE_NAME=‘" + tableName + "‘";
Long idVal = sqlSessionTemplateASS.selectOne("fetchSeqNextval", sql);
if (null == idVal) {
logger.error("/********************************");
logger.error("/获取id失败," + tableName + "表异常。请检查是否存在或者配为自增主键");
logger.error("/********************************");
return 0;
}
return idVal;
}
}
大概就是这个样子,注解我是直接拷贝的之前的CRUD框架,同样,为了效率和兼容MyBaits,这里我直接在类上用了泛型,而不是在方法上用泛型。之前在方法上用了泛型机制,这样的优点就是,只需要实例化一个类就好了。大概调用方法是:
//假设获取id为1的用户
UserPo user = get(UserPo.class,"id");
然而在效率上来说,则是大大的不好。因为每次方法调用时,都要将所传入的class进行解析,效率上大打折扣。在这里,我直接在类上加入了泛型,当一个Dao类初始化时,会自动对泛型字段进行解析,仅解析一次而已,之后每次使用这个Dao类的方法都是用解析好的资源。而不是每次调用方法就要反射一次。再配合Spring让其自动实例化,这样堪称完美。
那么,在使用过程中,则有了些许的改变,和Mybatis一样,需要些Dao,但是同样不用写实现类,准确的说,是直接集成已实现的Dao类。
加入我要写一个UserDao,那么,我不需要写接口和mapper文件,直接这样搞:
/**
* 一个基于公用Dao的UserDao
*/
@Repository
public class UserDao extends Dao<UserPo, Integer> {
//在这里,这个UserDao本身拥有了Dao的一些常用的增删改查方法。也可以重写或者增加一些特殊方法。
public List<UserPo> listGirl(){
//获取用户中的小姑娘,瞎写的。。
}
//再比如说我要重写一下list()这个方法
public List<UserPo> list(WhereParms where){
return super.list(where);
}
}
仅此而已,比直接用插件生成dao层还要方便一些,至少我感觉是这样。
日然后,Service层可以这么玩儿:
@Service
public class UserServiceImpl{
@Resource
private UserDao userDao;
/*
*根据姓名查找用户
*/
public List<UserPo> listUser(String name){
return userDao.list(Methor.where("name", C.Like, name));
}
}
还有一些若干的小功能,比如说自动日志啦,(在Service层的任意方法中,加入@Log注解可以记录这个方法的进栈时间、执行时所接收的参数,执行时所出现的异常,出栈时间等等)
再比如说自动事务(加入@Transactional注解后该方法拥有事务,一般和@Log一起用)
@Override
@Transactional
@Log
public ResultBean delUser(int uId, int appId, AdminUser user) {
// TODO Auto-generated method stub
ResultBean resultBean = new ResultBean();
resultBean.setResult(false);
AdminApp app = adminAppDao.get(appId);
if (null == app) {
resultBean.setCode(1);
resultBean.setMessage("App不存在");
return resultBean;
}
if (app.getAdminUserId() != user.getId()) {
resultBean.setCode(2);
resultBean.setMessage("无权操作");
return resultBean;
}
userFriendDao.del(Method.where("userId", C.EQ, uId));
userFriendInfoDao.del(Method.where("userId", C.EQ, uId).or("friendId", C.EQ, uId));
List<UserFriendGroup> list = userFriendGroupDao.list(Method.where("userId", C.EQ, uId));
for (UserFriendGroup userFriendGroup : list) {
userFriendDao.del(Method.where("friendGroupId", C.EQ, userFriendGroup.getId()));
userFriendGroupDao.del(userFriendGroup.getId());
}
appUserDao.del(uId);
app.setUserNum(app.getUserNum() - 1);
adminAppDao.update(app);
resultBean.setCode(0);
resultBean.setMessage("删除成功");
resultBean.setResult(true);
return resultBean;
}
—本次装逼结束,成功装完1个逼,成功捕获0个异常。成功率100%
目前暂未发现明什么Bug,阿海也再用这个封装的mybatis写一个自己的项目。等过段时间确定框架没有问题后,阿海再把该封装的Jar包以及源码发布。
届时,还请关注《通用DAO之MyBatis封装,封装通用的增删改查(三)》