频道栏目
首页 > 网络 > 云计算 > 正文

jdbc实现的orm工具类代码教程

2017-11-14 09:44:42      个评论    来源:zhaoyf7746的博客  
收藏   我要投稿

新公司的ORM框架使用了hibernate,但是我并不会,刚来项目老板催的紧,而且项目还是我独立开发,所以就自己用JDBC完成功能,但是你懂的,jdbc代码的冗余,操作的复杂都是我们初学就很烦的事儿了,所以花了半天时间写了一个BaseDao出来,代码如下:

import java.lang.reflect.ParameterizedType;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.uqiauto.util.ConnectionUtils;


/**
 * dao层父类
 * 封装了大部分的增删改查代码,但是关键实现都设置为抽象,继承此类需要提供具体实现
 * 因为父类try了SQLException,如果声明其他异常可能会导致程序终止
 * 所以如果需要限制访问权限,可以在子类实现中声明SQLException或其子类异常
 * 例:限制用户添加 throw new SQLException("This table is not allowed to be added");
 */
public abstract class BaseDao{

    private final Class entityClass;
    private final String entityClassName;

    @SuppressWarnings("unchecked")
    public BaseDao() {
        // 通过范型反射,获取在子类中定义的entityClass.
        this.entityClass = (Class) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        entityClassName = entityClass.getSimpleName();
    }

    /**
     * 获取实体类对象
     */
    public Class getEntityClass() {
        return entityClass;
    }

    /**
     * 获取实体类名(不包括包结构)
     */
    public String getEntityClassName() {
        return entityClassName;
    }

    /**
     * 调用子类方法的入口,子类中只需要提供toObject方法的实现
     * 查询无参实现
     * @param sql
     * @param values
     * @return
     */
    public T queryOne(String sql){
        T data = null;
        try {
            data = this.entityClass.newInstance();
            PreparedStatement pstmt = null;
            ResultSet rs = null;
            try {
                Connection conn = ConnectionUtils.getConnection();
                pstmt = conn.prepareStatement(sql);
                rs = pstmt.executeQuery();
                toObject(rs, data);
            } catch (SQLException e) {
                e.printStackTrace();
            }finally {
                ConnectionUtils.closeAll(rs, pstmt, Boolean.TRUE);
            }
        } catch (InstantiationException | IllegalAccessException e1) {
            e1.printStackTrace();
        }
        return data;
    }

    /**
     * 由子类继承,父类中不提供任何实现
     * @param rs    
     *      查询返回的结果集
     * @param data
     *      查询后保存的对象
     * @return
     *      参数data
     * @throws SQLException
     *      必须处理异常
     */
    protected abstract void toObject(ResultSet rs, T entity) throws SQLException;

    /**
     * 查询结果数量
     * @param sql
     * @return
     */
    public int queryCount(String sql){
        int count = 0;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        try {
            Connection conn = ConnectionUtils.getConnection();
            pstmt = conn.prepareStatement(sql);
            rs = pstmt.executeQuery();
            if(rs.next()){
                count = rs.getInt(1);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            ConnectionUtils.closeAll(rs, pstmt, Boolean.TRUE);
        }
        return count;
    }

    /**
     * 调用子类方法的入口,子类中只需要提供toObjectOfList方法的实现
     * 查询不带参数实现
     * @param sql
     * @param values
     * @return
     */
    public List queryList(String sql){
        List data = new ArrayList<>();
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        try {
            Connection conn = ConnectionUtils.getConnection();
            pstmt = conn.prepareStatement(sql);
            rs = pstmt.executeQuery();
            toObjectOfList(rs, data);
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            ConnectionUtils.closeAll(rs, pstmt, Boolean.TRUE);
        }
        return data;
    }

    /**
     * 分页查询,注意调用者必须验证返回值中的success函数
     * @param sql
     *      查询的SQL语句,不需要limit
     * @param curPage
     *      当前页码
     * @param pageSize
     *      每页显示条数
     * @return
     *      保存分页相关参数的map集合
     *      totalRows:数据条数
     *      page:页数
     *      data:返回数据
     *      success:验证分页 true->成功  false->失败
     */
    public Map queryListByPage(String sql, int curPage, int pageSize){
        Map map = new HashMap<>();
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        try {
            Connection conn = ConnectionUtils.getConnection();

            String countSql = sql.replace("*", "count(*)");
            pstmt = conn.prepareStatement(countSql);
            rs = pstmt.executeQuery();
            int count = rs.next() ? rs.getInt(1) : 0;
            int pageCount = count%pageSize == 0 ? count/pageSize : count/pageSize+1;
            map.put("totalRows", count);
            map.put("page", pageCount);

            List data = new ArrayList<>();
            int begin = (curPage-1)*pageSize+1;
            sql = sql.contains("where") ? sql + " limit " : sql + " where 1=1 limit ";
            sql = sql + begin + "," + pageSize;
            pstmt = conn.prepareStatement(sql);
            rs = pstmt.executeQuery();
            toObjectOfList(rs, data);
            map.put("data", data);
            map.put("success", true);
        } catch (SQLException e) {
            map.put("success", false);
            e.printStackTrace();
        }finally {
            ConnectionUtils.closeAll(rs, pstmt, Boolean.TRUE);
        }
        return map;
    }

    /**
     * 可以由子类继承,父类中所提供默认实现的内部是由子类实现的toObject方法
     * @param rs    
     *      查询返回的结果集
     * @param data
     *      查询后保存的集合
     * @return
     *      参数data
     * @throws SQLException
     *      必须处理异常
     */
    protected List toObjectOfList(ResultSet rs, List data) throws SQLException{
        if(rs != null && data != null){
            int rowCount = rs.last() ? rs.getRow() : 0;
            rs.beforeFirst();
            try {
                T t;
                for(int i=0; i< rowCount; i++){
                    t = this.entityClass.newInstance();
                    toObject(rs, t);
                    data.add(t);
                }
            } catch (InstantiationException | IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return data;
    }

    /**
     * 添加一条数据方法,参数放到SQL中直接执行
     * @param sql 执行SQL
     * @return 验证操作成功
     */
    public boolean insert(String sql){
        PreparedStatement pstmt = null;
        Connection conn =  null;
        try {
            conn = ConnectionUtils.getConnection();
            pstmt = conn.prepareStatement(sql);
            pstmt.executeUpdate();
            conn.commit();
            return true;
        } catch (SQLException e) {
            e.printStackTrace();
            try {
                conn.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            return false;
        }finally{
            ConnectionUtils.closeAll(null, pstmt, Boolean.TRUE);
        }
    }

    /**
     * 添加一条数据方法,参数的传递使用实体的值和实体对应dao层封装的赋值方法
     * @param sql 执行SQL
     * @param t  带参数的实体对象
     * @return 验证操作成功
     */
    public boolean insert(String sql, T entity){
        PreparedStatement pstmt = null;
        Connection conn =  null;
        try {
            conn = ConnectionUtils.getConnection();
            pstmt = conn.prepareStatement(sql);
            doInsertSetPstmt(pstmt, entity);
            pstmt.executeUpdate();
            conn.commit();
            return true;
        } catch (SQLException e) {
            e.printStackTrace();
            try {
                conn.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            return false;
        }finally{
            ConnectionUtils.closeAll(null, pstmt, Boolean.TRUE);
        }
    }

    /**
     * 批量添加数据,参数的传递使用实体的值和实体对应dao层封装的赋值方法
     * @param sql 执行SQL
     * @param dataList  保存带参数实体对象的集合
     * @return 验证操作成功
     */
    public boolean batchInsert(String sql, List dataList){
        PreparedStatement pstmt = null;
        Connection conn =  null;
        try {
            conn = ConnectionUtils.getConnection();
            pstmt = conn.prepareStatement(sql);
            conn.setAutoCommit(false);
            int count = 0;
            for (T t : dataList) {
                doInsertSetPstmt(pstmt, t);
                pstmt.addBatch();
                if(++count == 500){
                    pstmt.executeBatch();
                    count = 0;
                }
            }
            pstmt.executeBatch();
            conn.commit();
            return true;
        } catch (SQLException e) {
            e.printStackTrace();
            try {
                conn.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            return false;
        }finally{
            ConnectionUtils.closeAll(null, pstmt, Boolean.TRUE);
        }
    }

    /**
     * 由子类继承,父类中不提供任何实现
     * @param pstmt
     * @param entity
     * @throws SQLException 
     */
    protected abstract void doInsertSetPstmt(PreparedStatement pstmt, T entity) throws SQLException;

    /**
     * 删除SQL中的数据
     * @param sql
     * @return
     */
    public boolean delete(String sql){
        PreparedStatement pstmt = null;
        Connection conn =  null;
        try {
            conn = ConnectionUtils.getConnection();
            pstmt = conn.prepareStatement(sql);
            pstmt.executeUpdate();
            doDelete(conn);
            return true;
        } catch (SQLException e) {
            e.printStackTrace();
            try {
                conn.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            return false;
        }finally{
            ConnectionUtils.closeAll(null, pstmt, Boolean.TRUE);
        }
    }

    /**
     * 根据id集合批量删除
     * @param sql
     * @param ids
     * @return
     */
    public boolean batchDelete(String sql, List ids){
        PreparedStatement pstmt = null;
        Connection conn =  null;
        try {
            conn = ConnectionUtils.getConnection();
            pstmt = conn.prepareStatement(sql);
            conn.setAutoCommit(false);
            int count = 0;
            for (int i : ids) {
                pstmt.setInt(1, i);
                pstmt.addBatch();
                if(++count == 500){
                    pstmt.executeBatch();
                    count = 0;
                }
            }
            pstmt.executeBatch();
            doDelete(conn);
            return true;
        } catch (SQLException e) {
            e.printStackTrace();
            try {
                conn.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            return false;
        }finally{
            ConnectionUtils.closeAll(null, pstmt, Boolean.TRUE);
        }
    }
    protected abstract void doDelete(Connection conn) throws SQLException;

    /**
     * 修改SQL中的数据
     * @param sql
     * @return
     */
    public boolean update(String sql){
        PreparedStatement pstmt = null;
        Connection conn =  null;
        try {
            conn = ConnectionUtils.getConnection();
            pstmt = conn.prepareStatement(sql);
            pstmt.executeUpdate();
            conn.commit();
            return true;
        } catch (SQLException e) {
            e.printStackTrace();
            try {
                conn.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            return false;
        }finally{
            ConnectionUtils.closeAll(null, pstmt, Boolean.TRUE);
        }
    }

    /**
     * 批量修改集合中的所有数据
     * @param sql
     * @param dataList
     * @return
     */
    public boolean batchUpdate(String sql, List dataList){
        PreparedStatement pstmt = null;
        Connection conn =  null;
        try {
            conn = ConnectionUtils.getConnection();
            pstmt = conn.prepareStatement(sql);
            conn.setAutoCommit(false);
            int count = 0;
            for (T t : dataList) {
                doUpdateSetPstmt(pstmt, t);
                pstmt.addBatch();
                if(++count == 500){
                    pstmt.executeBatch();
                    count = 0;
                }
            }
            pstmt.executeBatch();
            conn.commit();
            return true;
        } catch (SQLException e) {
            e.printStackTrace();
            try {
                conn.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            return false;
        }finally{
            ConnectionUtils.closeAll(null, pstmt, Boolean.TRUE);
        }
    }

    protected abstract void doUpdateSetPstmt(PreparedStatement pstmt, T entity) throws SQLException;

    public java.sql.Date toSqlDate(Date date){
        java.sql.Date sqlDate = new java.sql.Date(new Date().getTime());
        if(date != null)
            sqlDate = new java.sql.Date(date.getTime());
        return sqlDate;
    }

    public Date toUtilDate(java.sql.Date sqlDate){
        Date date = new Date();
        if(sqlDate != null)
            date = new Date(sqlDate.getTime());
        return date;
    }

}

连接MySQL数据库的工具类:

import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

public class ConnectionUtils {

    // 线程单例

    private static ThreadLocal tl = new ThreadLocal();

    private static String url;

    private static String username;

    private static String password;

    static {
        // 装载驱动参数
        try {
            ClassLoader classLoader = ConnectionUtils.class.getClassLoader();
            InputStream is = classLoader.getResourceAsStream("standard.properties");
            Properties props = new Properties();
            props.load(is);
            url = props.getProperty("url");
            username = props.getProperty("username");
            password = props.getProperty("password");
            // 注册驱动
            Class.forName(props.getProperty("jdbc.driverName"));
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    public static Connection getConnection() throws SQLException{
        Connection con = tl.get();
        if (con == null || con.isClosed()) {
            con = DriverManager.getConnection(url, username, password);
            tl.set(con);
        }
        return con;
    }

    public static void closeConnection() {
        Connection conn = tl.get();
        if (conn == null)
            return;
        try {
            if (!conn.isClosed()) {
                //关闭数据库连接
                conn.close();
            }
        } catch (SQLException e) {
            System.err.println("#ERROR# :关闭数据库连接发生异常,请检查!\n" + e.getMessage());
        }
    }

    public static void closeAll(ResultSet rs, Statement stmt, boolean closeConn) {
        try {
            if (rs != null)
                rs.close();
            if (stmt != null)
                stmt.close();
            if(closeConn)
                closeConnection();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

实体类如下:

public class Area{
    //----------- object properties
    private Integer id;
    private String name;
    private Integer parent_id;
    private Byte sort;
    private Byte deep;
    private String city_code;
    private String region;
    private Integer status;
    private Integer ad_code;

    //------------ database columns
    public static final String ID = "AREA_ID";
    public static final String NAME = "AREA_NAME";
    public static final String PARENT_ID = "AREA_PARENT_ID";
    public static final String SORT = "AREA_SORT";
    public static final String DEEP = "AREA_DEEP";
    public static final String CITY_CODE = "CITY_CODE";
    public static final String REGION = "AREA_REGION";
    public static final String STATUS = "AREA_STATUS";
    public static final String AD_CODE = "AD_CODE";
    //------------ get or set ...

dao实现类如下:

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import com.entity.Area;

public class AreaDao extends BaseDao<Area>{

    @Override
    protected void toObject(ResultSet rs, Area data) throws SQLException{
        if(rs.next()){
            data.setId(rs.getInt(Area.ID));
            data.setName(rs.getString(Area.NAME));
            data.setParent_id(rs.getInt(Area.PARENT_ID));
            data.setSort(rs.getByte(Area.SORT));
            data.setDeep(rs.getByte(Area.DEEP));
            data.setCity_code(rs.getString(Area.CITY_CODE));
            data.setRegion(rs.getString(Area.REGION));
            data.setStatus(rs.getInt(Area.STATUS));
            data.setAd_code(rs.getInt(Area.AD_CODE));
        }
    }

    @Override
    protected void doInsertSetPstmt(PreparedStatement pstmt, Area t) throws SQLException {
        throw new SQLException("This table is not allowed to be added");
    }

    @Override
    protected void doUpdateSetPstmt(PreparedStatement pstmt, Area t) throws SQLException {
        throw new SQLException("This form is not allowed to be amended");
    }
    @Override
    protected void doDelete(Connection conn) throws SQLException {
        throw new SQLException("This form is not allowed to be deleted");
    }

}

我这里只是封装了一些冗余代码,并没有完成属性映射,一开始想着是用反射实现,后来发现时间不够。。。 然后就先写到这里了,写的过程想到我们可以用自定义注解来配置实体和表的映射,后面有时间会研究研究。

然后突然发现ORM框架其实不难(说这句话的时候我还没有研究过人家框架的源码,也许并不像我想的那么简单),也许以后有时间会自己完成一个ORM框架吧,先到这里,去赶项目了。

上一篇:变态青蛙跳代码实现教程
下一篇:最后一页
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站