栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

基于Spring JDBC 手写定制自己的ORM框架

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

基于Spring JDBC 手写定制自己的ORM框架

实现思路概述 ResultSet

说到ResultSet,对于有java开发经验的小伙伴自然是熟悉不过了。从ResultSet的取值大家都会,比如:

private static List select(String sql) {
       List result = new ArrayList<>();
       Connection con = null;          //连接对象
       PreparedStatement pstm = null;  //语句集
       ResultSet rs = null;            //结果集
       try {
           //1、加载驱动类
           Class.forName("com.mysql.jdbc.Driver");
           //2、建立连接
           con = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/spring-db-demo","root","123456");
            //3、创建语句集
            pstm =  con.prepareStatement(sql);
            //4、执行语句集
            rs = pstm.executeQuery();
            while (rs.next()){
                //纯粹的硬编码
                Member instance = new Member();
                instance.setId(rs.getLong("id"));
                instance.setName(rs.getString("name"));
                instance.setAge(rs.getInt("age"));
                instance.setAddr(rs.getString("addr"));
                result.add(instance);
            }
            //5、获取结果集
        }catch (Exception e){
            e.printStackTrace();
        }
        //6、关闭结果集、关闭语句集、关闭连接
        finally {
            try {
                rs.close();
                pstm.close();
                con.close();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        return result;
    }

这是我们之前没用框架的常规操作。但是随着业务和开发量的增加,我们可以发现在数据持久层这样的重复代码出现频次非常高。因此我们第一步想到的都是将非功能性代码和业务代码进行分离。大家首先想到的应该都是将封装数据的代码部分进行分离,类似如下代码:

private static List select(String sql) {
        List result = new ArrayList<>();
        Connection con = null;
        PreparedStatement pstm = null;
        ResultSet rs = null;
        try {
            //1、加载驱动类
            Class.forName("com.mysql.jdbc.Driver");
            //2、建立连接
            con = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/spring-db-demo","root","123456");
            //3、创建语句集
            pstm =  con.prepareStatement(sql);
            //4、执行语句集
            rs = pstm.executeQuery();
            while (rs.next()){
                Member instance = mapperRow(rs,rs.getRow());
                result.add(instance);
            }
            //5、获取结果集
        }catch (Exception e){
            e.printStackTrace();
        }
        //6、关闭结果集、关闭语句集、关闭连接
        finally {
            try {
                rs.close();
                pstm.close();
                con.close();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        return result;
    }

    private static Member mapperRow(ResultSet rs, int i) throws Exception {
        Member instance = new Member();
        instance.setId(rs.getLong("id"));
        instance.setName(rs.getString("name"));
        instance.setAge(rs.getInt("age"));
        instance.setAddr(rs.getString("addr"));
        return instance;
    }

但是在日常开发中,这样的代码逻辑重复率还是太高,上面的改造只能应用Member这个类,换一个类有需要重新封装,所以太过麻烦,这个时候我们不妨做出如下改进:

首先创建Member类:

@Entity
@Table(name = "t_member")
public class Member implements Serializable {
    @Id
    private Long id;
    private String name;
    private String addr;
    private Integer age;

    public Member() {
    }

    public Member(String name, String addr, Integer age) {
        this.name = name;
        this.addr = addr;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Member{" +
                "id=" + id +
                ", name='" + name + ''' +
                ", addr='" + addr + ''' +
                ", age=" + age +
                '}';
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddr() {
        return addr;
    }

    public void setAddr(String addr) {
        this.addr = addr;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}

对JDBC操作优化:

   public static void main(String[] args) {

        Member condition = new Member();
        condition.setName("TomCat");
        List result = select(condition);
        System.out.println(JSON.toJSONString(result,true));
    }

    public static List select(Object condition) {

        List result = new ArrayList<>();

        Class entityClass = condition.getClass();

        Connection con = null;          //连接对象
        PreparedStatement pstm = null;  //语句集
        ResultSet rs = null;            //结果集

        try {
            //1、加载驱动类
            Class.forName("com.mysql.jdbc.Driver");
            //2、建立连接
            con = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/spring-db-demo","root","123456");

            //用到反射
            Map getFieldNameByColumn = new HashMap();
            Map getColumnByFieldName = new HashMap();
            Field[] fields = entityClass.getDeclaredFields();
            for (Field field : fields) {
                field.setAccessible(true);
                String fieldName = field.getName();
                if(field.isAnnotationPresent(Column.class)){
                    Column column = field.getAnnotation(Column.class);
                    //别名优先
                    String columnName = column.name();
                    getFieldNameByColumn.put(columnName,fieldName);
                    getColumnByFieldName.put(fieldName,columnName);
                }else{
                    //默认属性名就是列名
                    getFieldNameByColumn.put(fieldName,fieldName);
                    getColumnByFieldName.put(fieldName,fieldName);
                }
            }

            StringBuffer sql = new StringBuffer();
            //3、创建语句集
            Table table = entityClass.getAnnotation(Table.class);
            sql.append("select * from " + table.name() + " where 1=1 ");
            for (Field field : fields) {

                Object value = field.get(condition);
                if(null != value){
                    if(String.class == field.getType()){
                        sql.append(" and " + getColumnByFieldName.get(field.getName()) + " = '" + value + "'");
                    }else{
                        sql.append(" and " + getColumnByFieldName.get(field.getName()) + " = " + value);
                    }
                    //其他依次类推
                }
            }

           pstm = con.prepareStatement(sql.toString());

            //4、执行,获取结果集
           rs = pstm.executeQuery();

           //metaDate 元信息
           int columnCounts = rs.getmetaData().getColumnCount();
           while (rs.next()){
               //一行一行往下读数据
               Object instance = entityClass.newInstance();  //反射

               for (int i = 1; i <= columnCounts; i++) {
                   String columnName = rs.getmetaData().getColumnName(i); //拿到列名

                   Field field = entityClass.getDeclaredField(getFieldNameByColumn.get(columnName));
                   field.setAccessible(true);

                   field.set(instance,rs.getObject(columnName));

               }
               result.add(instance);
           }
        }catch (Exception e){
            e.printStackTrace();
        }
        //6、关闭结果集、关闭语句集、关闭连接
        finally {
            try {
                rs.close();
                pstm.close();
                con.close();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        return result;
    }
 

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lmWSjHwe-1635688157372)(F:notesimagesimage-20211031120859589.png)]

巧妙地利用反射机制,读取class信息和Annotation信息,将数据库表中的列和类中的字段进行关联映射并赋值,以减少重复代码。

数据库设计

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3wP3UvBO-1635688157374)(F:notesimagesimage-20211031120019153.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bOeQyujs-1635688157375)(F:notesimagesimage-20211031120033163.png)]

为什么需要ORM框架

通过上面的操作,其实我们已经了解ORM框架的基本实现原理。ORM是指对象关系映射,映射的不仅仅只是对象值,还有对象和对象之间的关系。例如一对多、多对多、一对一这样的表关系。

目前市面上有众多ORM框架,比较主流的有hibernate,jpa,mybatis等框架。

名称特征描述
Hibernate全自动框架不需要写一句SQL
MyBatis半自动框架支持简单的映射,复杂关系需要自己写SQL
Spring JDBC纯手动框架所有的SQL都需要自己写,它提供了一套标准设计流程

为了更好的了解ORM框架的实现原理,所以直接手写一个我们自己的ORM框架。

ORM顶层设计 顶层接口设计

ORM框架,我们首先需要约定好顶层接口设计。只做单表操作;多表操作通过传SQL语句;

  • List select(QueryRule rule);
  • int delete(T entity)
  • int update(T entity)
  • int insert(T entity)
    • delete/update entity ID不能为空
    • insert entity ID不能为空
    • select entity非空值都作为查询条件拼接
    • queryRlue :类似JPA 构建查询条件
public interface baseDao {
    
    List select(QueryRule queryRule) throws Exception;

    
    Page select(QueryRule queryRule, int pageNo, int pageSize) throws Exception;

    
    List> selectBySql(String sql, Object... args) throws Exception;

    
    Page> selectBySqlToPage(String sql, Object[] param, int pageNo, int pageSize) throws Exception;


    
    boolean delete(T entity) throws Exception;

    
    int deleteAll(List list) throws Exception;

    
    PK insertAndReturnId(T entity) throws Exception;

    
    boolean insert(T entity) throws Exception;

    
    int insertAll(List list) throws Exception;

    
    boolean update(T entity) throws Exception;
}
搭建基础架构
public class Page implements Serializable {

    private static final long serialVersionUID = 1L;

    private static final int DEFAULT_PAGE_SIZE = 20;

    private int pageSize = DEFAULT_PAGE_SIZE; // 每页的记录数

    private long start; // 当前页第一条数据在List中的位置,从0开始

    private List rows; // 当前页中存放的记录,类型一般为List

    private long total; // 总记录数

    
    public Page() {
        this(0, 0, DEFAULT_PAGE_SIZE, new ArrayList());
    }

    
    public Page(long start, long totalSize, int pageSize, List rows) {
        this.pageSize = pageSize;
        this.start = start;
        this.total = totalSize;
        this.rows = rows;
    }

    
    public long getTotal() {
        return this.total;
    }

    public void setTotal(long total) {
        this.total = total;
    }

    
    public long getTotalPageCount() {
        if (total % pageSize == 0) {
            return total / pageSize;
        } else {
            return total / pageSize + 1;
        }
    }

    
    public int getPageSize() {
        return pageSize;
    }

    
    public List getRows() {
        return rows;
    }

    public void setRows(List rows) {
        this.rows = rows;
    }

    
    public long getPageNo() {
        return start / pageSize + 1;
    }

    
    public boolean hasNextPage() {
        return this.getPageNo() < this.getTotalPageCount() - 1;
    }

    
    public boolean hasPreviousPage() {
        return this.getPageNo() > 1;
    }

    
    protected static int getStartOfPage(int pageNo) {
        return getStartOfPage(pageNo, DEFAULT_PAGE_SIZE);
    }

    
    public static int getStartOfPage(int pageNo, int pageSize) {
        return (pageNo - 1) * pageSize;
    }

}
public class ResultMsg implements Serializable {

    private static final long serialVersionUID = 2635002588308355785L;

    private int status; //状态码,系统的返回码
    private String msg;  //状态码的解释
    private T data;  //放任意结果

    public ResultMsg() {
    }

    public ResultMsg(int status) {
        this.status = status;
    }

    public ResultMsg(int status, String msg) {
        this.status = status;
        this.msg = msg;
    }

    public ResultMsg(int status, T data) {
        this.status = status;
        this.data = data;
    }

    public ResultMsg(int status, String msg, T data) {
        this.status = status;
        this.msg = msg;
        this.data = data;
    }

    public int getStatus() {
        return status;
    }

    public void setStatus(int status) {
        this.status = status;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

}
public class Order {
    private boolean ascending; //升序还是降序
    private String propertyName; //哪个字段升序,哪个字段降序

    public String toString() {
        return propertyName + ' ' + (ascending ? "asc" : "desc");
    }

    protected Order(String propertyName, boolean ascending) {
        this.propertyName = propertyName;
        this.ascending = ascending;
    }

    public static Order asc(String propertyName) {
        return new Order(propertyName, true);
    }

    public static Order desc(String propertyName) {
        return new Order(propertyName, false);
    }

}
public final class QueryRule implements Serializable {
    private static final long serialVersionUID = 1L;
    public static final int ASC_ORDER = 101;
    public static final int DESC_ORDER = 102;
    public static final int LIKE = 1;
    public static final int IN = 2;
    public static final int NOTIN = 3;
    public static final int BETWEEN = 4;
    public static final int EQ = 5;
    public static final int NOTEQ = 6;
    public static final int GT = 7;
    public static final int GE = 8;
    public static final int LT = 9;
    public static final int LE = 10;
    public static final int ISNULL = 11;
    public static final int ISNOTNULL = 12;
    public static final int ISEMPTY = 13;
    public static final int ISNOTEMPTY = 14;
    public static final int AND = 201;
    public static final int OR = 202;
    private List ruleList = new ArrayList();
    private List queryRuleList = new ArrayList();
    private String propertyName;

    private QueryRule() {
    }

    private QueryRule(String propertyName) {
        this.propertyName = propertyName;
    }

    public static QueryRule getInstance() {
        return new QueryRule();
    }

    
    public QueryRule addAscOrder(String propertyName) {
        this.ruleList.add(new Rule(ASC_ORDER, propertyName));
        return this;
    }

    
    public QueryRule addDescOrder(String propertyName) {
        this.ruleList.add(new Rule(DESC_ORDER, propertyName));
        return this;
    }

    public QueryRule andIsNull(String propertyName) {
        this.ruleList.add(new Rule(ISNULL, propertyName).setAndOr(AND));
        return this;
    }

    public QueryRule andIsNotNull(String propertyName) {
        this.ruleList.add(new Rule(ISNOTNULL, propertyName).setAndOr(AND));
        return this;
    }

    public QueryRule andIsEmpty(String propertyName) {
        this.ruleList.add(new Rule(ISEMPTY, propertyName).setAndOr(AND));
        return this;
    }

    public QueryRule andIsNotEmpty(String propertyName) {
        this.ruleList.add(new Rule(ISNOTEMPTY, propertyName).setAndOr(AND));
        return this;
    }

    public QueryRule andLike(String propertyName, Object value) {
        this.ruleList.add(new Rule(LIKE, propertyName, new Object[]{value}).setAndOr(AND));
        return this;
    }

    public QueryRule andEqual(String propertyName, Object value) {
        this.ruleList.add(new Rule(EQ, propertyName, new Object[]{value}).setAndOr(AND));
        return this;
    }

    public QueryRule andBetween(String propertyName, Object... values) {
        this.ruleList.add(new Rule(BETWEEN, propertyName, values).setAndOr(AND));
        return this;
    }

    public QueryRule andIn(String propertyName, List values) {
        this.ruleList.add(new Rule(IN, propertyName, new Object[]{values}).setAndOr(AND));
        return this;
    }

    public QueryRule andIn(String propertyName, Object... values) {
        this.ruleList.add(new Rule(IN, propertyName, values).setAndOr(AND));
        return this;
    }

    public QueryRule andNotIn(String propertyName, List values) {
        this.ruleList.add(new Rule(NOTIN, propertyName, new Object[]{values}).setAndOr(AND));
        return this;
    }

    public QueryRule orNotIn(String propertyName, Object... values) {
        this.ruleList.add(new Rule(NOTIN, propertyName, values).setAndOr(OR));
        return this;
    }


    public QueryRule andNotEqual(String propertyName, Object value) {
        this.ruleList.add(new Rule(NOTEQ, propertyName, new Object[]{value}).setAndOr(AND));
        return this;
    }

    public QueryRule andGreaterThan(String propertyName, Object value) {
        this.ruleList.add(new Rule(GT, propertyName, new Object[]{value}).setAndOr(AND));
        return this;
    }

    public QueryRule andGreaterEqual(String propertyName, Object value) {
        this.ruleList.add(new Rule(GE, propertyName, new Object[]{value}).setAndOr(AND));
        return this;
    }

    public QueryRule andLessThan(String propertyName, Object value) {
        this.ruleList.add(new Rule(LT, propertyName, new Object[]{value}).setAndOr(AND));
        return this;
    }

    public QueryRule andLessEqual(String propertyName, Object value) {
        this.ruleList.add(new Rule(LE, propertyName, new Object[]{value}).setAndOr(AND));
        return this;
    }


    public QueryRule orIsNull(String propertyName) {
        this.ruleList.add(new Rule(ISNULL, propertyName).setAndOr(OR));
        return this;
    }

    public QueryRule orIsNotNull(String propertyName) {
        this.ruleList.add(new Rule(ISNOTNULL, propertyName).setAndOr(OR));
        return this;
    }

    public QueryRule orIsEmpty(String propertyName) {
        this.ruleList.add(new Rule(ISEMPTY, propertyName).setAndOr(OR));
        return this;
    }

    public QueryRule orIsNotEmpty(String propertyName) {
        this.ruleList.add(new Rule(ISNOTEMPTY, propertyName).setAndOr(OR));
        return this;
    }

    public QueryRule orLike(String propertyName, Object value) {
        this.ruleList.add(new Rule(LIKE, propertyName, new Object[]{value}).setAndOr(OR));
        return this;
    }

    public QueryRule orEqual(String propertyName, Object value) {
        this.ruleList.add(new Rule(EQ, propertyName, new Object[]{value}).setAndOr(OR));
        return this;
    }

    public QueryRule orBetween(String propertyName, Object... values) {
        this.ruleList.add(new Rule(BETWEEN, propertyName, values).setAndOr(OR));
        return this;
    }

    public QueryRule orIn(String propertyName, List values) {
        this.ruleList.add(new Rule(IN, propertyName, new Object[]{values}).setAndOr(OR));
        return this;
    }

    public QueryRule orIn(String propertyName, Object... values) {
        this.ruleList.add(new Rule(IN, propertyName, values).setAndOr(OR));
        return this;
    }

    public QueryRule orNotEqual(String propertyName, Object value) {
        this.ruleList.add(new Rule(NOTEQ, propertyName, new Object[]{value}).setAndOr(OR));
        return this;
    }

    public QueryRule orGreaterThan(String propertyName, Object value) {
        this.ruleList.add(new Rule(GT, propertyName, new Object[]{value}).setAndOr(OR));
        return this;
    }

    public QueryRule orGreaterEqual(String propertyName, Object value) {
        this.ruleList.add(new Rule(GE, propertyName, new Object[]{value}).setAndOr(OR));
        return this;
    }

    public QueryRule orLessThan(String propertyName, Object value) {
        this.ruleList.add(new Rule(LT, propertyName, new Object[]{value}).setAndOr(OR));
        return this;
    }

    public QueryRule orLessEqual(String propertyName, Object value) {
        this.ruleList.add(new Rule(LE, propertyName, new Object[]{value}).setAndOr(OR));
        return this;
    }


    public List getRuleList() {
        return this.ruleList;
    }

    public List getQueryRuleList() {
        return this.queryRuleList;
    }

    public String getPropertyName() {
        return this.propertyName;
    }

    protected class Rule implements Serializable {
        private static final long serialVersionUID = 1L;
        private int type;    //规则的类型
        private String property_name;
        private Object[] values;
        private int andOr = AND;

        public Rule(int paramInt, String paramString) {
            this.property_name = paramString;
            this.type = paramInt;
        }

        public Rule(int paramInt, String paramString,
                    Object[] paramArrayOfObject) {
            this.property_name = paramString;
            this.values = paramArrayOfObject;
            this.type = paramInt;
        }

        public Rule setAndOr(int andOr) {
            this.andOr = andOr;
            return this;
        }

        public int getAndOr() {
            return this.andOr;
        }

        public Object[] getValues() {
            return this.values;
        }

        public int getType() {
            return this.type;
        }

        public String getPropertyName() {
            return this.property_name;
        }
    }
}
 
基于SpringJDBC实现关键功能 
ClassMappings 
public class ClassMappings {

    private ClassMappings() {
    }

    static final Set> SUPPORTED_SQL_OBJECTS = new HashSet>();

    static {
        //只要这里写了的,默认支持自动类型转换
        Class[] classes = {
                boolean.class, Boolean.class,
                short.class, Short.class,
                int.class, Integer.class,
                long.class, Long.class,
                float.class, Float.class,
                double.class, Double.class,
                String.class,
                Date.class,
                Timestamp.class,
                BigDecimal.class
        };
        SUPPORTED_SQL_OBJECTS.addAll(Arrays.asList(classes));
    }

    static boolean isSupportedSQLObject(Class clazz) {
        return clazz.isEnum() || SUPPORTED_SQL_OBJECTS.contains(clazz);
    }

    public static Map findPublicGetters(Class clazz) {
        Map map = new HashMap();
        Method[] methods = clazz.getMethods();
        for (Method method : methods) {
            if (Modifier.isStatic(method.getModifiers()))
                continue;
            if (method.getParameterTypes().length != 0)
                continue;
            if (method.getName().equals("getClass"))
                continue;
            Class returnType = method.getReturnType();
            if (void.class.equals(returnType))
                continue;
            if (!isSupportedSQLObject(returnType)) {
                continue;
            }
            if ((returnType.equals(boolean.class)
                    || returnType.equals(Boolean.class))
                    && method.getName().startsWith("is")
                    && method.getName().length() > 2) {
                map.put(getGetterName(method), method);
                continue;
            }
            if (!method.getName().startsWith("get"))
                continue;
            if (method.getName().length() < 4)
                continue;
            map.put(getGetterName(method), method);
        }
        return map;
    }

    public static Field[] findFields(Class clazz) {
        return clazz.getDeclaredFields();
    }

    public static Map findPublicSetters(Class clazz) {
        Map map = new HashMap();
        Method[] methods = clazz.getMethods();
        for (Method method : methods) {
            if (Modifier.isStatic(method.getModifiers()))
                continue;
            if (!void.class.equals(method.getReturnType()))
                continue;
            if (method.getParameterTypes().length != 1)
                continue;
            if (!method.getName().startsWith("set"))
                continue;
            if (method.getName().length() < 4)
                continue;
            if (!isSupportedSQLObject(method.getParameterTypes()[0])) {
                continue;
            }
            map.put(getSetterName(method), method);
        }
        return map;
    }

    public static String getGetterName(Method getter) {
        String name = getter.getName();
        if (name.startsWith("is"))
            name = name.substring(2);
        else
            name = name.substring(3);
        return Character.toLowerCase(name.charAt(0)) + name.substring(1);
    }

    private static String getSetterName(Method setter) {
        String name = setter.getName().substring(3);
        return Character.toLowerCase(name.charAt(0)) + name.substring(1);
    }
}
QueryRuleSqlBuilder
public class QueryRuleSqlBuilder {
    private int CURR_INDEX = 0; //记录参数所在的位置
    private List properties; //保存列名列表
    private List values; //保存参数值列表
    private List orders; //保存排序规则列表

    private String whereSql = "";
    private String orderSql = "";
    private Object[] valueArr = new Object[]{};
    private Map valueMap = new HashMap();

    
    public String getWhereSql() {
        return this.whereSql;
    }

    
    public String getOrderSql() {
        return this.orderSql;
    }

    
    public Object[] getValues() {
        return this.valueArr;
    }

    
    public Map getValueMap() {
        return this.valueMap;
    }

    
    public QueryRuleSqlBuilder(QueryRule queryRule) {
        CURR_INDEX = 0;
        properties = new ArrayList();
        values = new ArrayList();
        orders = new ArrayList();
        for (QueryRule.Rule rule : queryRule.getRuleList()) {
            switch (rule.getType()) {
                case QueryRule.BETWEEN:
                    processBetween(rule);
                    break;
                case QueryRule.EQ:
                    processEqual(rule);
                    break;
                case QueryRule.LIKE:
                    processLike(rule);
                    break;
                case QueryRule.NOTEQ:
                    processNotEqual(rule);
                    break;
                case QueryRule.GT:
                    processGreaterThen(rule);
                    break;
                case QueryRule.GE:
                    processGreaterEqual(rule);
                    break;
                case QueryRule.LT:
                    processLessThen(rule);
                    break;
                case QueryRule.LE:
                    processLessEqual(rule);
                    break;
                case QueryRule.IN:
                    processIN(rule);
                    break;
                case QueryRule.NOTIN:
                    processNotIN(rule);
                    break;
                case QueryRule.ISNULL:
                    processIsNull(rule);
                    break;
                case QueryRule.ISNOTNULL:
                    processIsNotNull(rule);
                    break;
                case QueryRule.ISEMPTY:
                    processIsEmpty(rule);
                    break;
                case QueryRule.ISNOTEMPTY:
                    processIsNotEmpty(rule);
                    break;
                case QueryRule.ASC_ORDER:
                    processOrder(rule);
                    break;
                case QueryRule.DESC_ORDER:
                    processOrder(rule);
                    break;
                default:
                    throw new IllegalArgumentException("type " + rule.getType() + " not supported.");
            }
        }
        //拼装where语句
        appendWhereSql();
        //拼装排序语句
        appendOrderSql();
        //拼装参数值
        appendValues();
    }

    
    protected String removeOrders(String sql) {
        Pattern p = Pattern.compile("order\s*by[\w|\W|\s|\S]*", Pattern.CASE_INSENSITIVE);
        Matcher m = p.matcher(sql);
        StringBuffer sb = new StringBuffer();
        while (m.find()) {
            m.appendReplacement(sb, "");
        }
        m.appendTail(sb);
        return sb.toString();
    }

    
    protected String removeSelect(String sql) {
        if (sql.toLowerCase().matches("from\s+")) {
            int beginPos = sql.toLowerCase().indexOf("from");
            return sql.substring(beginPos);
        } else {
            return sql;
        }
    }

    
    private void processLike(QueryRule.Rule rule) {
        if (ArrayUtils.isEmpty(rule.getValues())) {
            return;
        }
        Object obj = rule.getValues()[0];

        if (obj != null) {
            String value = obj.toString();
            if (!StringUtils.isEmpty(value)) {
                value = value.replace('*', '%');
                obj = value;
            }
        }
        add(rule.getAndOr(), rule.getPropertyName(), "like", "%" + rule.getValues()[0] + "%");
    }

    
    private void processBetween(QueryRule.Rule rule) {
        if ((ArrayUtils.isEmpty(rule.getValues()))
                || (rule.getValues().length < 2)) {
            return;
        }
        add(rule.getAndOr(), rule.getPropertyName(), "", "between", rule.getValues()[0], "and");
        add(0, "", "", "", rule.getValues()[1], "");
    }

    
    private void processEqual(QueryRule.Rule rule) {
        if (ArrayUtils.isEmpty(rule.getValues())) {
            return;
        }
        add(rule.getAndOr(), rule.getPropertyName(), "=", rule.getValues()[0]);
    }

    
    private void processNotEqual(QueryRule.Rule rule) {
        if (ArrayUtils.isEmpty(rule.getValues())) {
            return;
        }
        add(rule.getAndOr(), rule.getPropertyName(), "<>", rule.getValues()[0]);
    }

    
    private void processGreaterThen(
            QueryRule.Rule rule) {
        if (ArrayUtils.isEmpty(rule.getValues())) {
            return;
        }
        add(rule.getAndOr(), rule.getPropertyName(), ">", rule.getValues()[0]);
    }

    
    private void processGreaterEqual(
            QueryRule.Rule rule) {
        if (ArrayUtils.isEmpty(rule.getValues())) {
            return;
        }
        add(rule.getAndOr(), rule.getPropertyName(), ">=", rule.getValues()[0]);
    }

    
    private void processLessThen(QueryRule.Rule rule) {
        if (ArrayUtils.isEmpty(rule.getValues())) {
            return;
        }
        add(rule.getAndOr(), rule.getPropertyName(), "<", rule.getValues()[0]);
    }

    
    private void processLessEqual(
            QueryRule.Rule rule) {
        if (ArrayUtils.isEmpty(rule.getValues())) {
            return;
        }
        add(rule.getAndOr(), rule.getPropertyName(), "<=", rule.getValues()[0]);
    }

    
    private void processIsNull(QueryRule.Rule rule) {
        add(rule.getAndOr(), rule.getPropertyName(), "is null", null);
    }

    
    private void processIsNotNull(QueryRule.Rule rule) {
        add(rule.getAndOr(), rule.getPropertyName(), "is not null", null);
    }

    
    private void processIsNotEmpty(QueryRule.Rule rule) {
        add(rule.getAndOr(), rule.getPropertyName(), "<>", "''");
    }

    
    private void processIsEmpty(QueryRule.Rule rule) {
        add(rule.getAndOr(), rule.getPropertyName(), "=", "''");
    }


    
    private void inAndNotIn(QueryRule.Rule rule, String name) {
        if (ArrayUtils.isEmpty(rule.getValues())) {
            return;
        }
        if ((rule.getValues().length == 1) && (rule.getValues()[0] != null)
                && (rule.getValues()[0] instanceof List)) {
            List list = (List) rule.getValues()[0];

            if ((list != null) && (list.size() > 0)) {
                for (int i = 0; i < list.size(); i++) {
                    if (i == 0 && i == list.size() - 1) {
                        add(rule.getAndOr(), rule.getPropertyName(), "", name + " (", list.get(i), ")");
                    } else if (i == 0 && i < list.size() - 1) {
                        add(rule.getAndOr(), rule.getPropertyName(), "", name + " (", list.get(i), "");
                    }
                    if (i > 0 && i < list.size() - 1) {
                        add(0, "", ",", "", list.get(i), "");
                    }
                    if (i == list.size() - 1 && i != 0) {
                        add(0, "", ",", "", list.get(i), ")");
                    }
                }
            }
        } else {
            Object[] list = rule.getValues();
            for (int i = 0; i < list.length; i++) {
                if (i == 0 && i == list.length - 1) {
                    add(rule.getAndOr(), rule.getPropertyName(), "", name + " (", list[i], ")");
                } else if (i == 0 && i < list.length - 1) {
                    add(rule.getAndOr(), rule.getPropertyName(), "", name + " (", list[i], "");
                }
                if (i > 0 && i < list.length - 1) {
                    add(0, "", ",", "", list[i], "");
                }
                if (i == list.length - 1 && i != 0) {
                    add(0, "", ",", "", list[i], ")");
                }
            }
        }
    }

    
    private void processNotIN(QueryRule.Rule rule) {
        inAndNotIn(rule, "not in");
    }

    
    private void processIN(QueryRule.Rule rule) {
        inAndNotIn(rule, "in");
    }

    
    private void processOrder(QueryRule.Rule rule) {
        switch (rule.getType()) {
            case QueryRule.ASC_ORDER:
                // propertyName非空
                if (!StringUtils.isEmpty(rule.getPropertyName())) {
                    orders.add(Order.asc(rule.getPropertyName()));
                }
                break;
            case QueryRule.DESC_ORDER:
                // propertyName非空
                if (!StringUtils.isEmpty(rule.getPropertyName())) {
                    orders.add(Order.desc(rule.getPropertyName()));
                }
                break;
            default:
                break;
        }
    }


    
    private void add(int andOr, String key, String split, Object value) {
        add(andOr, key, split, "", value, "");
    }

    
    private void add(int andOr, String key, String split, String prefix, Object value, String suffix) {
        String andOrStr = (0 == andOr ? "" : (QueryRule.AND == andOr ? " and " : " or "));
        properties.add(CURR_INDEX, andOrStr + key + " " + split + prefix + (null != value ? " ? " : " ") + suffix);
        if (null != value) {
            values.add(CURR_INDEX, value);
            CURR_INDEX++;
        }
    }


    
    private void appendWhereSql() {
        StringBuffer whereSql = new StringBuffer();
        for (String p : properties) {
            whereSql.append(p);
        }
        this.whereSql = removeSelect(removeOrders(whereSql.toString()));
    }

    
    private void appendOrderSql() {
        StringBuffer orderSql = new StringBuffer();
        for (int i = 0; i < orders.size(); i++) {
            if (i > 0 && i < orders.size()) {
                orderSql.append(",");
            }
            orderSql.append(orders.get(i).toString());
        }
        this.orderSql = removeSelect(removeOrders(orderSql.toString()));
    }

    
    private void appendValues() {
        Object[] val = new Object[values.size()];
        for (int i = 0; i < values.size(); i++) {
            val[i] = values.get(i);
            valueMap.put(i, values.get(i));
        }
        this.valueArr = val;
    }

}
 
baseDaoSupport 
public abstract class baseDaoSupport implements baseDao {
    private Logger log = Logger.getLogger(baseDaoSupport.class);

    private String tableName = "";

    private JdbcTemplate jdbcTemplateWrite;
    private JdbcTemplate jdbcTemplateReadOnly;

    //实现读写分离 操作两个数据源
    private DataSource dataSourceReadOnly;
    private DataSource dataSourceWrite;

    private EntityOperation op;

    @SuppressWarnings("unchecked")
    protected baseDaoSupport() {
        try {
            //    Class entityClass = (Class)((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
            Class entityClass = GenericsUtils.getSuperClassGenricType(getClass(), 0);
            op = new EntityOperation(entityClass, this.getPKColumn());
            this.setTableName(op.tableName);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    protected String getTableName() {
        return tableName;
    }

    protected DataSource getDataSourceReadOnly() {
        return dataSourceReadOnly;
    }

    protected DataSource getDataSourceWrite() {
        return dataSourceWrite;
    }

    
    protected void setTableName(String tableName) {
        if (StringUtils.isEmpty(tableName)) {
            this.tableName = op.tableName;
        } else {
            this.tableName = tableName;
        }
    }

    protected void setDataSourceWrite(DataSource dataSourceWrite) {
        this.dataSourceWrite = dataSourceWrite;
        jdbcTemplateWrite = new JdbcTemplate(dataSourceWrite);
    }

    protected void setDataSourceReadOnly(DataSource dataSourceReadOnly) {
        this.dataSourceReadonly = dataSourceReadOnly;
        jdbcTemplateReadonly = new JdbcTemplate(dataSourceReadOnly);
    }

    private JdbcTemplate jdbcTemplateReadOnly() {
        return this.jdbcTemplateReadOnly;
    }

    private JdbcTemplate jdbcTemplateWrite() {
        return this.jdbcTemplateWrite;
    }


    
    protected void restoreTableName() {
        this.setTableName(op.tableName);
    }

    
    protected Map parse(T entity) {
        return op.parse(entity);
    }


    
    protected T get(PK id) throws Exception {
        return (T) this.doLoad(id, this.op.rowMapper);
    }

    
    protected List getAll() throws Exception {
        String sql = "select " + op.allColumn + " from " + getTableName();
        return this.jdbcTemplateReadOnly().query(sql, this.op.rowMapper, new HashMap());
    }

    
    public PK insertAndReturnId(T entity) throws Exception {
        return (PK) this.doInsertRuturnKey(parse(entity));
    }

    
    public boolean insert(T entity) throws Exception {
        return this.doInsert(parse(entity));
    }


    
    protected boolean save(T entity) throws Exception {
        PK pkValue = (PK) op.pkField.get(entity);
        if (this.exists(pkValue)) {
            return this.doUpdate(pkValue, parse(entity)) > 0;
        } else {
            return this.doInsert(parse(entity));
        }
    }

    
    protected PK saveAndReturnId(T entity) throws Exception {
        Object o = op.pkField.get(entity);
        if (null == o) {
            return (PK) this.doInsertRuturnKey(parse(entity));
            //return (PK)id;
        }
        PK pkValue = (PK) o;
        if (this.exists(pkValue)) {
            this.doUpdate(pkValue, parse(entity));
            return pkValue;
        } else {
            return (PK) this.doInsertRuturnKey(parse(entity));
        }
    }

    
    public boolean update(T entity) throws Exception {
        return this.doUpdate(op.pkField.get(entity), parse(entity)) > 0;
    }

    
    protected int update(String sql, Object... args) throws Exception {
        return jdbcTemplateWrite().update(sql, args);
    }

    
    protected int update(String sql, Map paramMap) throws Exception {
        return jdbcTemplateWrite().update(sql, paramMap);
    }

    
    public int insertAll(List list) throws Exception {
        int count = 0, len = list.size(), step = 50000;
        Map pm = op.mappings;
        int maxPage = (len % step == 0) ? (len / step) : (len / step + 1);
        for (int i = 1; i <= maxPage; i++) {
            Page page = pagination(list, i, step);
            String sql = "insert into " + getTableName() + "(" + op.allColumn + ") values ";// (" + valstr.toString() + ")";
            StringBuffer valstr = new StringBuffer();
            Object[] values = new Object[pm.size() * page.getRows().size()];
            for (int j = 0; j < page.getRows().size(); j++) {
                if (j > 0 && j < page.getRows().size()) {
                    valstr.append(",");
                }
                valstr.append("(");
                int k = 0;
                for (PropertyMapping p : pm.values()) {
                    values[(j * pm.size()) + k] = p.getter.invoke(page.getRows().get(j));
                    if (k > 0 && k < pm.size()) {
                        valstr.append(",");
                    }
                    valstr.append("?");
                    k++;
                }
                valstr.append(")");
            }
            int result = jdbcTemplateWrite().update(sql + valstr.toString(), values);
            count += result;
        }

        return count;
    }


    protected boolean replaceOne(T entity) throws Exception {
        return this.doReplace(parse(entity));
    }


    protected int replaceAll(List list) throws Exception {
        int count = 0, len = list.size(), step = 50000;
        Map pm = op.mappings;
        int maxPage = (len % step == 0) ? (len / step) : (len / step + 1);
        for (int i = 1; i <= maxPage; i++) {
            Page page = pagination(list, i, step);
            String sql = "replace into " + getTableName() + "(" + op.allColumn + ") values ";// (" + valstr.toString() + ")";
            StringBuffer valstr = new StringBuffer();
            Object[] values = new Object[pm.size() * page.getRows().size()];
            for (int j = 0; j < page.getRows().size(); j++) {
                if (j > 0 && j < page.getRows().size()) {
                    valstr.append(",");
                }
                valstr.append("(");
                int k = 0;
                for (PropertyMapping p : pm.values()) {
                    values[(j * pm.size()) + k] = p.getter.invoke(page.getRows().get(j));
                    if (k > 0 && k < pm.size()) {
                        valstr.append(",");
                    }
                    valstr.append("?");
                    k++;
                }
                valstr.append(")");
            }
            int result = jdbcTemplateWrite().update(sql + valstr.toString(), values);
            count += result;
        }
        return count;
    }


    
    public boolean delete(T entity) throws Exception {
        return this.doDelete(op.pkField.get(entity)) > 0;
    }

    
    public int deleteAll(List list) throws Exception {
        String pkName = op.pkField.getName();
        int count = 0, len = list.size(), step = 1000;
        Map pm = op.mappings;
        int maxPage = (len % step == 0) ? (len / step) : (len / step + 1);
        for (int i = 1; i <= maxPage; i++) {
            StringBuffer valstr = new StringBuffer();
            Page page = pagination(list, i, step);
            Object[] values = new Object[page.getRows().size()];

            for (int j = 0; j < page.getRows().size(); j++) {
                if (j > 0 && j < page.getRows().size()) {
                    valstr.append(",");
                }
                values[j] = pm.get(pkName).getter.invoke(page.getRows().get(j));
                valstr.append("?");
            }

            String sql = "delete from " + getTableName() + " where " + pkName + " in (" + valstr.toString() + ")";
            int result = jdbcTemplateWrite().update(sql, values);
            count += result;
        }
        return count;
    }

    
    protected void deleteByPK(PK id) throws Exception {
        this.doDelete(id);
    }

    
// protected boolean delete(PK id)  throws Exception {
//    return this.doDelete(id) > 0;
// }

    
    protected T selectUnique(String propertyName, Object value) throws Exception {
        QueryRule queryRule = QueryRule.getInstance();
        queryRule.andEqual(propertyName, value);
        return this.selectUnique(queryRule);
    }

    
    protected boolean exists(PK id) throws Exception {
        return null != this.doLoad(id, this.op.rowMapper);
    }

    
    protected long getCount(QueryRule queryRule) throws Exception {
        QueryRuleSqlBuilder bulider = new QueryRuleSqlBuilder(queryRule);
        Object[] values = bulider.getValues();
        String ws = removeFirstAnd(bulider.getWhereSql());
        String whereSql = ("".equals(ws) ? ws : (" where " + ws));
        String countSql = "select count(1) from " + getTableName() + whereSql;
        return (Long) this.jdbcTemplateReadOnly().queryForMap(countSql, values).get("count(1)");
    }

    
    protected T getMax(String propertyName) throws Exception {
        QueryRule queryRule = QueryRule.getInstance();
        queryRule.addDescOrder(propertyName);
        Page result = this.select(queryRule, 1, 1);
        if (null == result.getRows() || 0 == result.getRows().size()) {
            return null;
        } else {
            return result.getRows().get(0);
        }
    }

    
    public List select(QueryRule queryRule) throws Exception {
        QueryRuleSqlBuilder bulider = new QueryRuleSqlBuilder(queryRule);
        String ws = removeFirstAnd(bulider.getWhereSql());
        String whereSql = ("".equals(ws) ? ws : (" where " + ws));
        String sql = "select " + op.allColumn + " from " + getTableName() + whereSql;
        Object[] values = bulider.getValues();
        String orderSql = bulider.getOrderSql();
        orderSql = (StringUtils.isEmpty(orderSql) ? " " : (" order by " + orderSql));
        sql += orderSql;
        log.debug(sql);
        return (List) this.jdbcTemplateReadOnly().query(sql, this.op.rowMapper, values);
    }

    
    protected List> selectBySql(String sql, Map pamam) throws Exception {
        return this.jdbcTemplateReadOnly().queryForList(sql, pamam);
    }

    
    protected Map selectUniqueBySql(String sql, Map pamam) throws Exception {
        List> list = selectBySql(sql, pamam);
        if (list.size() == 0) {
            return null;
        } else if (list.size() == 1) {
            return list.get(0);
        } else {
            throw new IllegalStateException("findUnique return " + list.size() + " record(s).");
        }
    }

    
    public List> selectBySql(String sql, Object... args) throws Exception {
        return this.jdbcTemplateReadOnly().queryForList(sql, args);
    }

    
    protected Map selectUniqueBySql(String sql, Object... args) throws Exception {
        List> list = selectBySql(sql, args);
        if (list.size() == 0) {
            return null;
        } else if (list.size() == 1) {
            return list.get(0);
        } else {
            throw new IllegalStateException("findUnique return " + list.size() + " record(s).");
        }
    }

    
    protected List> selectBySql(String sql, List list) throws Exception {
        return this.jdbcTemplateReadOnly().queryForList(sql, list.toArray());
    }

    
    protected Map selectUniqueBySql(String sql, List listParam) throws Exception {
        List> listMap = selectBySql(sql, listParam);
        if (listMap.size() == 0) {
            return null;
        } else if (listMap.size() == 1) {
            return listMap.get(0);
        } else {
            throw new IllegalStateException("findUnique return " + listMap.size() + " record(s).");
        }
    }

    
    public Page select(QueryRule queryRule, final int pageNo, final int pageSize) throws Exception {
        QueryRuleSqlBuilder bulider = new QueryRuleSqlBuilder(queryRule);
        Object[] values = bulider.getValues();
        String ws = removeFirstAnd(bulider.getWhereSql());
        String whereSql = ("".equals(ws) ? ws : (" where " + ws));
        String countSql = "select count(1) from " + getTableName() + whereSql;
        long count = (Long) this.jdbcTemplateReadOnly().queryForMap(countSql, values).get("count(1)");
        if (count == 0) {
            return new Page();
        }
        long start = (pageNo - 1) * pageSize;
        // 有数据的情况下,继续查询
        String orderSql = bulider.getOrderSql();
        orderSql = (StringUtils.isEmpty(orderSql) ? " " : (" order by " + orderSql));
        String sql = "select " + op.allColumn + " from " + getTableName() + whereSql + orderSql + " limit " + start + "," + pageSize;
        List list = (List) this.jdbcTemplateReadOnly().query(sql, this.op.rowMapper, values);
        log.debug(sql);
        return new Page(start, count, pageSize, list);
    }


    
    protected Page> selectBySqlToPage(String sql, Map param, final int pageNo, final int pageSize) throws Exception {
        String countSql = "select count(1) from (" + sql + ") a";
        long count = (Long) this.jdbcTemplateReadOnly().queryForMap(countSql, param).get("count(1)");

//    long count = this.jdbcTemplateReadonly().queryForMap(countSql, param);
        if (count == 0) {
            return new Page>();
        }
        long start = (pageNo - 1) * pageSize;
        // 有数据的情况下,继续查询
        sql = sql + " limit " + start + "," + pageSize;
        List> list = (List>) this.jdbcTemplateReadOnly().queryForList(sql, param);
        log.debug(sql);
        return new Page>(start, count, pageSize, list);
    }


    
    public Page> selectBySqlToPage(String sql, Object[] param, final int pageNo, final int pageSize) throws Exception {
        String countSql = "select count(1) from (" + sql + ") a";

        long count = (Long) this.jdbcTemplateReadOnly().queryForMap(countSql, param).get("count(1)");
//    long count = this.jdbcTemplateReadonly().queryForLong(countSql, param);
        if (count == 0) {
            return new Page>();
        }
        long start = (pageNo - 1) * pageSize;
        sql = sql + " limit " + start + "," + pageSize;
        List> list = (List>) this.jdbcTemplateReadOnly().queryForList(sql, param);
        log.debug(sql);
        return new Page>(start, count, pageSize, list);
    }

    
    protected T selectUnique(Map properties) throws Exception {
        QueryRule queryRule = QueryRule.getInstance();
        for (String key : properties.keySet()) {
            queryRule.andEqual(key, properties.get(key));
        }
        return selectUnique(queryRule);
    }

    
    protected T selectUnique(QueryRule queryRule) throws Exception {
        List list = select(queryRule);
        if (list.size() == 0) {
            return null;
        } else if (list.size() == 1) {
            return list.get(0);
        } else {
            throw new IllegalStateException("findUnique return " + list.size() + " record(s).");
        }
    }


    
    protected Page pagination(List objList, int pageNo, int pageSize) throws Exception {
        List objectArray = new ArrayList(0);
        int startIndex = (pageNo - 1) * pageSize;
        int endIndex = pageNo * pageSize;
        if (endIndex >= objList.size()) {
            endIndex = objList.size();
        }
        for (int i = startIndex; i < endIndex; i++) {
            objectArray.add(objList.get(i));
        }
        return new Page(startIndex, objList.size(), pageSize, objectArray);
    }

    
    protected void mergeList(List pojoList, List poList, String idName) throws Exception {
        mergeList(pojoList, poList, idName, false);
    }

    
    protected void mergeList(List pojoList, List poList, String idName, boolean isCopyNull) throws Exception {
        Map map = new HashMap();
        Map pm = op.mappings;
        for (Object element : pojoList) {
            Object key;
            try {
                key = pm.get(idName).getter.invoke(element);
                map.put(key, element);
            } catch (Exception e) {
                throw new IllegalArgumentException(e);
            }
        }
        for (Iterator it = poList.iterator(); it.hasNext(); ) {
            T element = it.next();
            try {
                Object key = pm.get(idName).getter.invoke(element);
                if (!map.containsKey(key)) {
                    delete(element);
                    it.remove();
                } else {
                    DataUtils.copySimpleObject(map.get(key), element, isCopyNull);
                }
            } catch (Exception e) {
                throw new IllegalArgumentException(e);
            }
        }
        T[] pojoArray = (T[]) pojoList.toArray();
        for (int i = 0; i < pojoArray.length; i++) {
            T element = pojoArray[i];
            try {
                Object key = pm.get(idName).getter.invoke(element);
                if (key == null) {
                    poList.add(element);
                }
            } catch (Exception e) {
                throw new IllegalArgumentException(e);
            }
        }
    }

    private String removeFirstAnd(String sql) {
        if (StringUtils.isEmpty(sql)) {
            return sql;
        }
        return sql.trim().toLowerCase().replaceAll("^\s*and", "") + " ";
    }

    private EntityOperation getOp() {
        return this.op;
    }


    
    private  T populate(ResultSet rs, T obj) {
        try {
            ResultSetmetaData metaData = rs.getmetaData(); // 取得结果集的元元素
            int colCount = metaData.getColumnCount(); // 取得所有列的个数
            Field[] fields = obj.getClass().getDeclaredFields();
            for (int i = 0; i < fields.length; i++) {
                Field f = fields[i];
                // rs的游标从1开始,需要注意
                for (int j = 1; j <= colCount; j++) {
                    Object value = rs.getObject(j);
                    String colName = metaData.getColumnName(j);
                    if (!f.getName().equalsIgnoreCase(colName)) {
                        continue;
                    }

                    // 如果列名中有和字段名一样的,则设置值
                    try {
                        BeanUtils.copyProperty(obj, f.getName(), value);
                    } catch (Exception e) {
                        log.warn("BeanUtils.copyProperty error, field name: "
                                + f.getName() + ", error: " + e);
                    }

                }
            }
        } catch (Exception e) {
            log.warn("populate error...." + e);
        }
        return obj;
    }

    
    private  T selectForObject(String sql, RowMapper mapper,
                                  Object... args) {
        List results = this.jdbcTemplateReadOnly().query(sql, mapper, args);
        return DataAccessUtils.singleResult(results);
    }

    protected byte[] getBlobColumn(ResultSet rs, int columnIndex)
            throws SQLException {
        try {
            Blob blob = rs.getBlob(columnIndex);
            if (blob == null) {
                return null;
            }

            InputStream is = blob.getBinaryStream();
            ByteArrayOutputStream bos = new ByteArrayOutputStream();

            if (is == null) {
                return null;
            } else {
                byte buffer[] = new byte[64];
                int c = is.read(buffer);
                while (c > 0) {
                    bos.write(buffer, 0, c);
                    c = is.read(buffer);
                }
                return bos.toByteArray();
            }
        } catch (IOException e) {
            throw new SQLException(
                    "Failed to read BLOB column due to IOException: "
                            + e.getMessage());
        }
    }

    protected void setBlobColumn(PreparedStatement stmt, int parameterIndex,
                                 byte[] value) throws SQLException {
        if (value == null) {
            stmt.setNull(parameterIndex, Types.BLOB);
        } else {
            stmt.setBinaryStream(parameterIndex,
                    new ByteArrayInputStream(value), value.length);
        }
    }

    protected String getClobColumn(ResultSet rs, int columnIndex)
            throws SQLException {
        try {
            Clob clob = rs.getClob(columnIndex);
            if (clob == null) {
                return null;
            }

            StringBuffer ret = new StringBuffer();
            InputStream is = clob.getAsciiStream();

            if (is == null) {
                return null;
            } else {
                byte buffer[] = new byte[64];
                int c = is.read(buffer);
                while (c > 0) {
                    ret.append(new String(buffer, 0, c));
                    c = is.read(buffer);
                }
                return ret.toString();
            }
        } catch (IOException e) {
            throw new SQLException(
                    "Failed to read CLOB column due to IOException: "
                            + e.getMessage());
        }
    }

    protected void setClobColumn(PreparedStatement stmt, int parameterIndex,
                                 String value) throws SQLException {
        if (value == null) {
            stmt.setNull(parameterIndex, Types.CLOB);
        } else {
            stmt.setAsciiStream(parameterIndex,
                    new ByteArrayInputStream(value.getBytes()), value.length());
        }
    }

    
    private  Page simplePageQuery(String sql, RowMapper rowMapper, Map args, long pageNo, long pageSize) {
        long start = (pageNo - 1) * pageSize;
        return simplePageQueryByStart(sql, rowMapper, args, start, pageSize);
    }

    
    private  Page simplePageQueryByStart(String sql, RowMapper rowMapper, Map args, long start, long pageSize) {
        // 首先查询总数
        String countSql = "select count(*) " + removeSelect(removeOrders(sql));

        long count = (Long) this.jdbcTemplateReadOnly().queryForMap(countSql, args).get("count(1)");
//    long count = this.jdbcTemplateReadonly().queryForLong(countSql, args);
        if (count == 0) {
            log.debug("no result..");
            return new Page();
        }
        // 有数据的情况下,继续查询
        sql = sql + " limit " + start + "," + pageSize;
        log.debug(StringUtils.format("[Execute SQL]sql:{0},params:{1}", sql, args));
        List list = this.jdbcTemplateReadOnly().query(sql, rowMapper, args);
        return new Page(start, count, (int) pageSize, list);
    }

    protected long queryCount(String sql, Map args) {
        String countSql = "select count(1) " + removeSelect(removeOrders(sql));

        return (Long) this.jdbcTemplateReadOnly().queryForMap(countSql, args).get("count(1)");
    }

    protected  List simpleListQueryByStart(String sql, RowMapper rowMapper,
                                                 Map args, long start, long pageSize) {

        sql = sql + " limit " + start + "," + pageSize;
        log.debug(StringUtils.format("[Execute SQL]sql:{0},params:{1}", sql, args));
        List list = this.jdbcTemplateReadOnly().query(sql, rowMapper, args);
        if (list == null) {
            return new ArrayList();
        }
        return list;
    }

    
    private Page simplePageQueryNotT(String sql, RowMapper rm, Map args, long pageNo, long pageSize) {
        // 首先查询总数
        String countSql = "select count(*) " + removeSelect(removeOrders(sql));
        long count = (Long) this.jdbcTemplateReadOnly().queryForMap(countSql, args).get("count(1)");
        if (count == 0) {
            log.debug("no result..");
            return new Page();
        }
        // 有数据的情况下,继续查询
        long start = (pageNo - 1) * pageSize;
        sql = sql + " limit " + start + "," + pageSize;
        log.debug(StringUtils.format("[Execute SQL]sql:{0},params:{1}", sql, args));
        List list = this.jdbcTemplateReadOnly().query(sql, rm, args);
        return new Page(start, count, (int) pageSize, list);
    }

    
    private String removeOrders(String sql) {
        Pattern p = Pattern.compile("order\s*by[\w|\W|\s|\S]*", Pattern.CASE_INSENSITIVE);
        Matcher m = p.matcher(sql);
        StringBuffer sb = new StringBuffer();
        while (m.find()) {
            m.appendReplacement(sb, "");
        }
        m.appendTail(sb);
        return sb.toString();
    }

    
    private String removeSelect(String sql) {
        int beginPos = sql.toLowerCase().indexOf("from");
        return sql.substring(beginPos);
    }


    private long getMaxId(String table, String column) {
        String sql = "SELECt max(" + column + ") FROM " + table + " ";
        long maxId = (Long) this.jdbcTemplateReadOnly().queryForMap(sql).get("max(" + column + ")");
        return maxId;
    }

    
    private String makeSimpleUpdateSql(String tableName, String pkName, Object pkValue, Map params) {
        if (StringUtils.isEmpty(tableName) || params == null || params.isEmpty()) {
            return "";
        }

        StringBuffer sb = new StringBuffer();
        sb.append("update ").append(tableName).append(" set ");
        //添加参数
        Set set = params.keySet();
        int index = 0;
        for (String key : set) {
//        sb.append(key).append(" = :").append(key);
            sb.append(key).append(" = ?");
            if (index != set.size() - 1) {
                sb.append(",");
            }
            index++;
        }
//    sb.append(" where ").append(pkName).append(" = :").append(pkName) ;
        sb.append(" where ").append(pkName).append(" = ?");
        params.put("where_" + pkName, params.get(pkName));

        return sb.toString();
    }


    
    private String makeSimpleUpdateSql(String pkName, Object pkValue, Map params) {
        if (StringUtils.isEmpty(getTableName()) || params == null || params.isEmpty()) {
            return "";
        }

        StringBuffer sb = new StringBuffer();
        sb.append("update ").append(getTableName()).append(" set ");
        //添加参数
        Set set = params.keySet();
        int index = 0;
        for (String key : set) {
            sb.append(key).append(" = :").append(key);
            if (index != set.size() - 1) {
                sb.append(",");
            }
            index++;
        }
        sb.append(" where ").append(pkName).append(" = :").append(pkName);

        return sb.toString();
    }


    
    private String makeSimpleReplaceSql(String tableName, Map params) {
        if (StringUtils.isEmpty(tableName) || params == null || params.isEmpty()) {
            return "";
        }
        StringBuffer sb = new StringBuffer();
        sb.append("replace into ").append(tableName);

        StringBuffer sbKey = new StringBuffer();
        StringBuffer sbValue = new StringBuffer();

        sbKey.append("(");
        sbValue.append("(");
        //添加参数
        Set set = params.keySet();
        int index = 0;
        for (String key : set) {
            sbKey.append(key);
            sbValue.append(" :").append(key);
            if (index != set.size() - 1) {
                sbKey.append(",");
                sbValue.append(",");
            }
            index++;
        }
        sbKey.append(")");
        sbValue.append(")");

        sb.append(sbKey).append("VALUES").append(sbValue);

        return sb.toString();
    }

    
    private String makeSimpleReplaceSql(String tableName, Map params, List values) {
        if (StringUtils.isEmpty(tableName) || params == null || params.isEmpty()) {
            return "";
        }
        StringBuffer sb = new StringBuffer();
        sb.append("replace into ").append(tableName);

        StringBuffer sbKey = new StringBuffer();
        StringBuffer sbValue = new StringBuffer();

        sbKey.append("(");
        sbValue.append("(");
        //添加参数
        Set set = params.keySet();
        int index = 0;
        for (String key : set) {
            sbKey.append(key);
            sbValue.append(" ?");
            if (index != set.size() - 1) {
                sbKey.append(",");
                sbValue.append(",");
            }
            index++;
            values.add(params.get(key));
        }
        sbKey.append(")");
        sbValue.append(")");

        sb.append(sbKey).append("VALUES").append(sbValue);

        return sb.toString();
    }


    
    private String makeSimpleInsertSql(String tableName, Map params) {
        if (StringUtils.isEmpty(tableName) || params == null || params.isEmpty()) {
            return "";
        }
        StringBuffer sb = new StringBuffer();
        sb.append("insert into ").append(tableName);

        StringBuffer sbKey = new StringBuffer();
        StringBuffer sbValue = new StringBuffer();

        sbKey.append("(");
        sbValue.append("(");
        //添加参数
        Set set = params.keySet();
        int index = 0;
        for (String key : set) {
            sbKey.append(key);
//       sbValue.append(" :").append(key);
            sbValue.append(" ?");
            if (index != set.size() - 1) {
                sbKey.append(",");
                sbValue.append(",");
            }
            index++;
        }
        sbKey.append(")");
        sbValue.append(")");

        sb.append(sbKey).append("VALUES").append(sbValue);

        return sb.toString();
    }

    
    private String makeSimpleInsertSql(String tableName, Map params, List values) {
        if (StringUtils.isEmpty(tableName) || params == null || params.isEmpty()) {
            return "";
        }
        StringBuffer sb = new StringBuffer();
        sb.append("insert into ").append(tableName);

        StringBuffer sbKey = new StringBuffer();
        StringBuffer sbValue = new StringBuffer();

        sbKey.append("(");
        sbValue.append("(");
        //添加参数
        Set set = params.keySet();
        int index = 0;
        for (String key : set) {
            sbKey.append(key);
            sbValue.append(" ?");
            if (index != set.size() - 1) {
                sbKey.append(",");
                sbValue.append(",");
            }
            index++;
            values.add(params.get(key));
        }
        sbKey.append(")");
        sbValue.append(")");

        sb.append(sbKey).append("VALUES").append(sbValue);

        return sb.toString();
    }


    private Serializable doInsertRuturnKey(Map params) {
        final List values = new ArrayList();
        final String sql = makeSimpleInsertSql(getTableName(), params, values);
        KeyHolder keyHolder = new GeneratedKeyHolder();
        final JdbcTemplate jdbcTemplate = new JdbcTemplate(getDataSourceWrite());
        try {

            jdbcTemplate.update(new PreparedStatementCreator() {
                public PreparedStatement createPreparedStatement(

                        Connection con) throws SQLException {
                    PreparedStatement ps = con.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);

                    for (int i = 0; i < values.size(); i++) {
                        ps.setObject(i + 1, values.get(i) == null ? null : values.get(i));

                    }
                    return ps;
                }

            }, keyHolder);
        } catch (DataAccessException e) {
            log.error("error", e);
        }


        if (keyHolder == null) {
            return "";
        }


        Map keys = keyHolder.getKeys();
        if (keys == null || keys.size() == 0 || keys.values().size() == 0) {
            return "";
        }
        Object key = keys.values().toArray()[0];
        if (key == null || !(key instanceof Serializable)) {
            return "";
        }
        if (key instanceof Number) {
            //Long k = (Long) key;
            Class clazz = key.getClass();
//       return clazz.cast(key);
            return (clazz == int.class || clazz == Integer.class) ? ((Number) key).intValue() : ((Number) key).longValue();


        } else if (key instanceof String) {
            return (String) key;
        } else {
            return (Serializable) key;
        }


    }


    
    private String makeDefaultSimpleUpdateSql(Object pkValue, Map params) {
        return this.makeSimpleUpdateSql(getTableName(), getPKColumn(), pkValue, params);
    }

    
    private String makeDefaultSimpleInsertSql(Map params) {
        return this.makeSimpleInsertSql(this.getTableName(), params);
    }

    
    private Object doLoad(String tableName, String pkName, Object pkValue, RowMapper rm) {
        StringBuffer sb = new StringBuffer();
        sb.append("select * from ").append(tableName).append(" where ").append(pkName).append(" = ?");
        List list = this.jdbcTemplateReadOnly().query(sb.toString(), rm, pkValue);
        if (list == null || list.isEmpty()) {
            return null;
        }
        return list.get(0);
    }

    
    private  T doLoad(Object pkValue, RowMapper rowMapper) {
        Object obj = this.doLoad(getTableName(), getPKColumn(), pkValue, rowMapper);
        if (obj != null) {
            return (T) obj;
        }
        return null;
    }


    
    private int doDelete(String tableName, String pkName, Object pkValue) {
        StringBuffer sb = new StringBuffer();
        sb.append("delete from ").append(tableName).append(" where ").append(pkName).append(" = ?");
        int ret = this.jdbcTemplateWrite().update(sb.toString(), pkValue);
        return ret;
    }

    
    private int doDelete(Object pkValue) {
        return this.doDelete(getTableName(), getPKColumn(), pkValue);
    }

    
    private int doUpdate(String tableName, String pkName, Object pkValue, Map params) {
        params.put(pkName, pkValue);
        String sql = this.makeSimpleUpdateSql(tableName, pkName, pkValue, params);
        int ret = this.jdbcTemplateWrite().update(sql, params.values().toArray());
        return ret;
    }

    
    private int doUpdate(String pkName, Object pkValue, Map params) {
        params.put(pkName, pkValue);
        String sql = this.makeSimpleUpdateSql(pkName, pkValue, params);
        int ret = this.jdbcTemplateWrite().update(sql, params.values().toArray());
        return ret;
    }

    
    private int doUpdate(Object pkValue, Map params) {
        //
        String sql = this.makeDefaultSimpleUpdateSql(pkValue, params);
        params.put(this.getPKColumn(), pkValue);
        int ret = this.jdbcTemplateWrite().update(sql, params.values().toArray());
        return ret;
    }


    private boolean doReplace(Map params) {
        String sql = this.makeSimpleReplaceSql(this.getTableName(), params);
        int ret = this.jdbcTemplateWrite().update(sql, params.values().toArray());
        return ret > 0;
    }

    private boolean doReplace(String tableName, Map params) {
        String sql = this.makeSimpleReplaceSql(tableName, params);
        int ret = this.jdbcTemplateWrite().update(sql, params.values().toArray());
        return ret > 0;
    }


    
    private boolean doInsert(String tableName, Map params) {
        String sql = this.makeSimpleInsertSql(tableName, params);
        int ret = this.jdbcTemplateWrite().update(sql, params.values().toArray());
        return ret > 0;
    }

    
    private boolean doInsert(Map params) {
        String sql = this.makeSimpleInsertSql(this.getTableName(), params);
        int ret = this.jdbcTemplateWrite().update(sql, params.values().toArray());
        return ret > 0;
    }

    
    protected abstract String getPKColumn();

    protected abstract void setDataSource(DataSource dataSource);

    private Map convertMap(Object obj) {
        Map map = new HashMap();

        List getters = TypeUtils.computeGetters(obj.getClass(), null);
        for (int i = 0, len = getters.size(); i < len; i++) {
            FieldInfo fieldInfo = getters.get(i);
            String name = fieldInfo.getName();
            try {
                Object value = fieldInfo.get(obj);
                map.put(name, value);
            } catch (Exception e) {
                log.error(String.format("convertMap error object:%s  field: %s", obj.toString(), name));
            }
        }

        return map;
    }

}
 
动态数据源切换的底层原理 

可以使用动态数据源实现分库分表的相关操作。

DynamicDataSourceEntry
public class DynamicDataSourceEntry {

    // 默认数据源
    public final static String DEFAULT_SOURCE = null;

    private final static ThreadLocal local = new ThreadLocal();

    
    public void clear() {
        local.remove();
    }

    
    public String get() {
        return local.get();
    }

    
    public void restore(JoinPoint join) {
        local.set(DEFAULT_SOURCE);
    }

    
    public void restore() {
        local.set(DEFAULT_SOURCE);
    }

    
    public void set(String source) {
        local.set(source);
    }

    
    public void set(int year) {
        local.set("DB_" + year);
    }
}
DynamicDataSource
public class DynamicDataSource extends AbstractRoutingDataSource {

    //entry的目的,主要是用来给每个数据源打个标记
    private DynamicDataSourceEntry dataSourceEntry;

    @Override
    protected Object determineCurrentLookupKey() {
        return this.dataSourceEntry.get();
    }

    public void setDataSourceEntry(DynamicDataSourceEntry dataSourceEntry) {
        this.dataSourceEntry = dataSourceEntry;
    }

    public DynamicDataSourceEntry getDataSourceEntry() {
        return this.dataSourceEntry;
    }

}
业务代码 实体类

member类创建过,在创建一个order类。

@Entity
@Table(name = "t_order")
public class Order implements Serializable {
    private Long id;
    @Column(name = "mid")
    private Long memberId;
    private String detail;
    private Long createTime;
    private String createTimeFmt;

    @Override
    public String toString() {
        return "Order{" +
                "id=" + id +
                ", memberId=" + memberId +
                ", detail='" + detail + ''' +
                ", createTime=" + createTime +
                ", createTimeFmt='" + createTimeFmt + ''' +
                '}';
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Long getMemberId() {
        return memberId;
    }

    public void setMemberId(Long memberId) {
        this.memberId = memberId;
    }

    public String getDetail() {
        return detail;
    }

    public void setDetail(String detail) {
        this.detail = detail;
    }

    public Long getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Long createTime) {
        this.createTime = createTime;
    }

    public String getCreateTimeFmt() {
        return createTimeFmt;
    }

    public void setCreateTimeFmt(String createTimeFmt) {
        this.createTimeFmt = createTimeFmt;
    }
}
Dao类
@Repository
public class MemberDao extends baseDaoSupport {

    @Override
    protected String getPKColumn() {
        return "id";
    }


    @Resource(name = "dataSource")
    public void setDataSource(DataSource dataSource) {
        super.setDataSourceReadOnly(dataSource);
        super.setDataSourceWrite(dataSource);
    }


    public List selectAll() throws Exception {
        QueryRule queryRule = QueryRule.getInstance();
//        queryRule.andLike("name","cc%");
        return super.select(queryRule);
    }


    public Page selectForPage(int pageNo, int pageSize) throws Exception {
        QueryRule queryRule = QueryRule.getInstance();
        queryRule.andLike("name", "cc%");
        Page page = super.select(queryRule, pageNo, pageSize);
        return page;
    }

    public void select() throws Exception {
        String sql = "";
        List> result = super.selectBySql(sql);
//        System.out.println(JSON.parseObject(JSON.toJSonString(result)),Member.class);
    }

    public boolean insert(Member entity) throws Exception {
//        super.setTableName("t_mmmmm");
        return super.insert(entity);
    }
}
@Repository
public class OrderDao extends baseDaoSupport {

    private SimpleDateFormat yearFormat = new SimpleDateFormat("yyyy");
    private SimpleDateFormat monthFormat = new SimpleDateFormat("MM");
    private SimpleDateFormat fullDataFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    private DynamicDataSource dataSource;

    @Override
    protected String getPKColumn() {
        return "id";
    }

    
    @Resource(name = "dynamicDataSource")
    public void setDataSource(DataSource dataSource) {
        this.dataSource = (DynamicDataSource) dataSource;
        this.setDataSourceReadOnly(dataSource);
        this.setDataSourceWrite(dataSource);
    }

    public boolean insertOne(Order order) throws Exception {
        Date date = null;
        if (order.getCreateTime() == null) {
            date = new Date();
            order.setCreateTime(date.getTime());
        } else {
            date = new Date(order.getCreateTime());
        }
        //分库 : 根据年份将数据插入到不同的库中
        Integer dbRouter = Integer.valueOf(yearFormat.format(date));
        System.out.println("自动分配到【DB_" + dbRouter + "】数据源");
        this.dataSource.getDataSourceEntry().set(dbRouter);

        order.setCreateTimeFmt(fullDataFormat.format(date));

        //分表 : 根据月份将输入插入到不同的表中
        String month = monthFormat.format(date);

        super.setTableName(super.getTableName() + "_" + String.valueOf(Integer.parseInt(month) - 1));

        Long orderId = super.insertAndReturnId(order);

        //还原默认表名
        super.restoreTableName();

        order.setId(orderId);
        return orderId > 0;
    }

}
相关配置文件

直接复制项目中的即可,但是需要修改db.propertise和application-db.xml文件中的相关信息。

需要注意的是如果采用分库分表,需要提前创建相关库表。

如spring-db-2021库t_order_4表。

项目地址

orm-mini

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号