通用DAO之MyBatis封装,封装通用的增删改查(二)

先给大家推荐一个好玩的网站MyChatGPT(免梯子,国内直接用,不需要OpenAI账号):https://chat.icoding.ink/

曾经发过一篇文章,大概写的就是阿海多么多么厉害,见到某位同事在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生成这一块和注解这一块基本上可以复制粘贴。

PS: 这篇文章中提到的内容已经经过N个版本的迭代和优化,新的代码已经整合成依赖库并发布到Maven中央仓库。

<dependency>
   <groupId>com.easymybatis.freamwork</groupId>
   <artifactId>spring-easymybatis-core</artifactId>
   <version>0.0.4.RELEASE</version>
</dependency>

该文章中以下内容皆为最初的版本,与当前版本相差甚多,早已不在维护,项目已开源,获取新信息或问题反馈请到GitHub: https://github.com/onlyGuo/easymybatis

通用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 719348277@qq.com
 * @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封装,封装通用的增删改查(三)》

评论 68
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值