DAO层通用实现,结果集ResultSet转化为javaBean的反射实现,自动生成javaBean

在学习持久层框架之前,反复编写dao层代码编烦了,就自己实现了一个能方便地根据数据库表创建javaBean,并实现其增删改查,结果集转化为List集合,sql编译语句里参数赋值的自动化的“框架”。本文所使用的数据库是mysql自带的simple data里的sakila数据库

先看一下使用效果:

  1. 先编写并运行测试类创建javaBean:
    Country,City,Address,Customer
package com.iss.db.dao.toolkit;

import java.sql.ResultSet;
import java.sql.SQLException;

import org.junit.Test;

import com.iss.db.dao.connectdb.OffLineConn;
import com.iss.db.dao.dbinfo.DBConfig;

/**
 * 创建javaBean源文件(下面的代码还可以进一步封装)
 */
public class CreateJavaBeanSource {
   
   
    @Test
public void test01() throws Exception{
        ResultSet rs = TableTool.execQuery(new OffLineConn(new DBConfig()).getConn().prepareStatement("select * from country where 1>2"));
        String descTable = DBTool.descTable(rs);
        System.out.println(descTable);
        DBTool.createClazzToSource(rs, "src/main/java", "com.iss.db.bean.Country", "country");
        rs = TableTool.execQuery(new OffLineConn(new DBConfig()).getConn().prepareStatement("select * from city where 1>2"));

      descTable = DBTool.descTable(rs);
    System.out.println(descTable);
    DBTool.createClazzToSource(rs, "src/main/java", "com.iss.db.bean.City", "city");

      rs = TableTool.execQuery(new OffLineConn(new DBConfig()).getConn().prepareStatement("select * from address where 1>2"));
      descTable = DBTool.descTable(rs);
    System.out.println(descTable);
    DBTool.createClazzToSource(rs, "src/main/java", "com.iss.db.bean.Address", "address");

      rs = TableTool.execQuery(new OffLineConn(new DBConfig()).getConn().prepareStatement("select * from customer where 1>2"));
      descTable = DBTool.descTable(rs);
    System.out.println(descTable);
    DBTool.createClazzToSource(rs, "src/main/java", "com.iss.db.bean.Customer", "customer");
}
}

上述代码中DBTool.createClazzToSource(包含所有列的结果集,工程src名,javaBean全类名,数据库表名),还可以进一步封装使之更易用

  1. 编写上述4个javaBean对应的DAO类:
    1. CounryDao.java :

package com.iss.db.dao.tablemanager;
import com.iss.db.bean.Country;
import com.iss.db.dao.tableinfo.TableDic;
public class CountryDao extends TableManager{
   
   
    public CountryDao(){
        super(Country.class,new TableDic("country_id", "country", "country"));
    }
}

2.CityDao.java

package com.iss.db.dao.tablemanager;
import com.iss.db.bean.City;
import com.iss.db.dao.tableinfo.TableDic;
public class CityDao extends TableManager {
   
   
    public CityDao() {
        super(City.class, new TableDic("city_id", "city", "city", "country_id"));
    }
}

3.AddressDao.java

public class AddressDao extends TableManager{
   
   
    public AddressDao(){
        super(Address.class, new TableDic("address_id", "address", "address","address2","district","city_id","postal_code","phone"));
    }
}

4.CustomerDao.java

public class CustomerDao extends TableManager{
   
   
    public CustomerDao(){
        super(Customer.class,new TableDic("customer_id", "customer","store_id","first_name","last_name","email","address_id","active"));
    }
}
**上述代码其实只是在给TableManager传入参数,参数提供javaBean的class信息,以及数据库表的主要信息new TableDic(“主键”,”表明”,”更新操作的字段1”,”更新操作的字段2”,……)**

实现过程:

**1. 核心问题:遍历结果集创建java对象很麻烦,各种重复操作,如何省去?**

1.学过反射,想到可以通过反射调用对象的set方法为之赋值。
2.如过自动赋值,那么对于ResultSet的每一行,如果遍历它的各个字段,查阅发现ResultSet.getMetaData()方法可以获取各个列的信息(名称,类型)。
3.调用javaBean对象的set方法需要考虑传入参数类型, 那么没问题, setmethod.getGenericParameterTypes()[0].getTypeName()可以办到。
4. SQL数据库类型明显要比java里的类型多,需要做个类型对应。
5. 如何自动生成java源文件,那不就是io文件流嘛,拼接好javaBean字符串写入文件即可。

**代码组织结构如下:** ![代码组织结构](https://img-blog.youkuaiyun.com/20170803161700485?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2luYXRfMzQ4MjAyOTI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
对该功能实现分多个层是为了易于修改和扩展,上图中HeadPicDao.java,MyTool.java与本文介绍的东西无关。
1)包DAO层细分了几个包:
    1.  dao.connectdb: 获取数据库连接的抽象,可以是永久连接,可以使连接池,OffLineConn是对GetDBConn的一个开发时实现,实际中可以使用数据库连接池,远程连接等来实现。
    2.  dao.tableinfo: 数据库表关键信息的抽象,关键信息包括(主键,表名,更新操作的字段[]),是创建某个表DAO层唯一需要的输入,TableDic是对TableInfo的实现,也可以用从配置文件获取表信息的方法实现TableInfo。
    3.  dao.dbinfo: 对数据库信息的抽象,关键信息包括(驱动名,数据库url,用户名,密码),这里就把数据库的信息写死在了DBconfig.java了,如果想换成从配置文件获取,只需要写一个从配置文件获取数据库信息的类实现DBInfo接口即可(策略模式)。
    4.  dao.toolkit:工具类,获得连接后可以使用的工具DBTool,制定了表之后可用的工具TableTool,数据格式转化工具MyTool(实现json, javaBean, ResultSet 等值间的转化)
    5.  dao.tablemanager: 每个表Dao的模板类,以及每个数据表对应的继承类,在继承里指定对应的javaBean和tableinfo信息即可
2) 特点:
    1.  根据数据库表自动创建javaBean文件。
    2.  ResultSet到javaBean的变化依据数据库字段名在javaBean中找对应的set方法,判断set方法的输入参数类型和数据库表类型是否一致(类型匹配),匹配则调用这个set方法进行赋值。
    3.  更新类操作根据初始化时指定的数据库表信息里的主键信息、更新字段信息进行,程序根据这些字段名自动从javaBean中提取信息进行更新或者插入操作。
    4.  查询自动包装成javaBean,根据的是数据库表的属性。
    5.  综上,javaBean可以任意添加成员变量,其它方法,只需要满足javaBean里的get方法是数据库属性的超集、javaBean里的set方法是tableinfo指定更新属性的超集即可。

核心代码如下 ( 其余代码会在后面贴上 )

**1. 结果集转化为javaBean集合(MyTool.java里面的部分代码)**

数据类型映射表:

    // 类型对照表,试着用反射实现javaBean装箱操作
        public final static Map<String, String> TYPE_DIC = new HashMap<String, String>() {
    {
        put("VARCHAR", "java.lang.String");
        put("VARCHAR2", "java.lang.String");
        put("CHAR", "java.lang.String");
        put("TEXT", "java.lang.String");
        put("MEDIUMTEXT", "java.lang.String");
        put("LONGTEXT", "java.lang.String");
        put("INT", "java.lang.Integer,int");
        put("SMALLINT", "java.lang.Short,short");
        put("TINYINT", "java.lang.Short,short,java.lang.Boolean");
        put("SMALLINT UNSIGNED","java.lang.Short,short");
        put("FLOAT", "java.lang.Float,float");
        put("DECIMAL", "java.lang.Float,folat");
        put("DOUBLE", "java.lang.Double,double");
        put("YEAR", "java.sql.Date,java.util.Date");
        put("DATE", "java.sql.Date,java.util.Date");
        put("TIME", "java.sql.Date,java.util.Date");
        put("DATETIME", "java.sql.Timestamp,java.util.Date");
        put("TIMESTAMP", "java.sql.Timestamp,java.util.Date");
        put("ID", "java.lang.Long,long");
        put("BIT", "java.lang.Boolean,boolean");
        put("BINARY", "java.lang.Boolean,boolean");
        put("BOOLEAN", "java.lang.Boolean,boolean");
        put("BIGINT", "java.math.BigInteger,long");
        put("INTEGER", "java.lang.Integer,int");// 或者long ?
        put("BLOB", "java.lang.String");// 或者 java.lang.byte[] ?

        put("GEOMETRY","java.lang.String");
        put("TINYINT UNSIGNED","java.lang.Integer,int,java.lang.Byte,buty");
    }
};
        // 可以通过 valueOf(String arg)装箱的基本数据类型
        public final static Map<String, String> BASIC_TYPE = new HashMap<String, String>() {
            {
                put(
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值