手把手教你如何自定义DAO框架(重量级干货)

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS MySQL,高可用系列 2核4GB
简介: 手把手教你如何自定义DAO框架(重量级干货)

描述:本篇博客,主要是对于目前实际web项目开发中,对于数据库操作的一些基本方法的封装,通过这样的方式,可以使得开发更加简单,减少代码量,也便于维护和阅读。其中,主要是讲解了三种不同情况的封装方法,都是自身实际开发过程中,进行积累的,当然,还有很多不足之处,但是基本够项目的基本开发。


一:非框架的DAO层封装

其中包含的知识点:

1:连接池

2:数据源

3:反射

4:数据库元数据对象

5:基本的jdbc知识


封装步骤:


(1)导入dbcp数据源包


image.png

(2)编写properties文件,并且命令为dbcpconfig.properties

#连接设置  
   driverClassName=com.mysql.jdbc.Driver  
   url=jdbc:mysql://localhost:3306/填写要使用的数据库  
   username=填写自己的mysql账号  
   password=填写自己的mysql密码  
   #<!-- 初始化连接 -->  
   initialSize=10  
   #最大连接数量  
   maxActive=50  
   #<!-- 最大空闲连接 -->  
   maxIdle=20  
   #<!-- 最小空闲连接 -->  
   minIdle=5  
   #<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 -->  
   maxWait=60000  
   #JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:[属性名=property;]  
   #注意:"user" 与 "password" 两个属性会被明确地传递,因此这里不需要包含他们。  
   connectionProperties=useUnicode=true;characterEncoding=gbk  
   #指定由连接池所创建的连接的自动提交(auto-commit)状态。  
   defaultAutoCommit=true  
   #driver default 指定由连接池所创建的连接的只读(read-only)状态。  
   #如果没有设置该值,则“setReadOnly”方法将不被调用。(某些驱动并不支持只读模式,如:Informix)  
   defaultReadOnly=false  
   #driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。  
   #可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE  
   defaultTransactionIsolation=READ_UNCOMMITTED


(3)编写DBCP工具类

public class DBCPUtils {  
   private static DataSource ds ;    
   static {  
       //将配置文件加载进来  
       InputStream in = DBCPUtils.class.getClassLoader().getResourceAsStream("dbcpconfig.properties") ;  
       Properties props = new Properties() ;  
       try {  
           props.load(in) ;  
           ds = BasicDataSourceFactory.createDataSource(props) ;  
       } catch (Exception e) {  
           throw new RuntimeException("服务器忙") ;  
       }  
   }  
   //提供获取连接的方法  
   public static Connection getConnection(){  
       try {  
           return ds.getConnection() ;  
       } catch (SQLException e) {  
           throw new RuntimeException("服务器忙") ;  
       }  
   }  
}


(4)编写基本DAO层方法封装

//自定义框架  
public class BaseDao{  
   // 执行添改删语句  
   public boolean update(String sql, Object... params) {  
       // 拿到连接对象  
       Connection conn = DBCPUtils.getConnection();  
       int t = 0;  
       try {  
           // 创建预处理命令对象  
           PreparedStatement pstmt = conn.prepareStatement(sql);  
           // 对?进行赋值  
           // 获取ParameterMetaData对象  
           ParameterMetaData pmd = pstmt.getParameterMetaData();  
           // 拿到?的个数  
           int n = pmd.getParameterCount();  
           if (n > 0) {  
               // sql语句里有?号  
               if (params == null || params.length != n) {  
                   throw new RuntimeException("参数的个数不匹配");  
               }  
               // 依次给每个?赋值  
               for (int i = 0; i < n; i++) {  
                   pstmt.setObject(i + 1, params[i]);  
               }  
           }  
           t = pstmt.executeUpdate();  
       } catch (SQLException e) {  
           e.printStackTrace();  
       } finally {  
           try {  
               conn.close(); // 还回池中了  
           } catch (SQLException e) {  
               // TODO Auto-generated catch block  
               e.printStackTrace();  
           }  
       }  
       return t > 0 ? true : false;  
   }  
   // 执行查询(返回的结果可能是一个或者多个,或者为null,这个就具体根据返回结果再进行处理即可)  
   public Object queryOne(String sql,Class clazz, Object... params) {  
       // 拿到连接对象  
       Connection conn = DBCPUtils.getConnection();  
       try {  
           // 创建预处理命令对象  
           PreparedStatement pstmt = conn.prepareStatement(sql);  
           // 对?进行赋值  
           // 获取ParameterMetaData对象  
           ParameterMetaData pmd = pstmt.getParameterMetaData();  
           // 拿到?的个数  
           int n = pmd.getParameterCount();  
           if (n > 0) {  
               // sql语句里有?号  
               if (params == null || params.length != n) {  
                   throw new RuntimeException("参数的个数不匹配");  
               }  
               // 依次给每个?赋值  
               for (int i = 0; i < n; i++) {  
                   pstmt.setObject(i + 1, params[i]);  
               }  
           }  
           ResultSet rs = pstmt.executeQuery();  
           //返回的结果可能是一个或者多个,或者为null  
           return new ResultSetListenerHandlerImpl().handler(rs, clazz) ;  
       } catch (SQLException e) {  
           throw new RuntimeException() ;  
       } finally {  
           try {  
               conn.close(); // 还回池中了  
           } catch (SQLException e) {  
               // TODO Auto-generated catch block  
               e.printStackTrace();  
           }  
       }  
   }  
}


(5)查询返回结果集与实体bean的封装对象ResultSetListenerHandlerImpl

//只适用于结果集有多条记录的情况  
//对象的属性名和表中的字段名应当一致  
public class ResultSetListenerHandlerImpl{  
   public Object handler(ResultSet rs, Class clazz) {        
       List<Object> list = new ArrayList<Object>() ;  
       //拿到结果集的元数据对象  
       try {  
           while(rs.next()){  
               ResultSetMetaData rsmd = rs.getMetaData() ;  
               //拿到公有多少列  
               int columnCount = rsmd.getColumnCount() ;  
               //先创建对象  
               Object obj = clazz.newInstance() ;  
               for (int i = 0; i < columnCount; i++) {  
                   //拿到列名  
                   String columnName = rsmd.getColumnName(i+1) ;        
                   //拿到对象对应的属性  
                   Field field = clazz.getDeclaredField(columnName) ;  
                   //设置私有属性可以访问  
                   field.setAccessible(true) ;  
                   //拿到此列对应的值  
                   Object objectValue = rs.getObject(i+1) ;  
                   //给属性赋值  
                   field.set(obj, objectValue) ;  
               }  
               list.add(obj) ;  
           }  
           return list ;  
       } catch (Exception e) {  
           throw new RuntimeException() ;  
       }  
   }  
}


上面这个是返回一个List的情况,如果只想是返回单个对象,那么很简单,稍微处理一下就可以用下面这个类来实现:

//只适用于结果集只有一条记录的情况  
//对象的属性名和表中的字段名应当一致  
public class ResultSetHandlerImpl {  
   public Object handler(ResultSet rs, Class clazz) {  
       //拿到结果集的元数据对象  
       try {  
           if(rs.next()){  
               ResultSetMetaData rsmd = rs.getMetaData() ;  
               //拿到公有多少列  
               int columnCount = rsmd.getColumnCount() ;  
               //先创建对象  
               Object obj = clazz.newInstance() ;  
               for (int i = 0; i < columnCount; i++) {  
                   //拿到列名  
                   String columnName = rsmd.getColumnName(i+1) ;        
                   //拿到对象对应的属性  
                   Field field = clazz.getDeclaredField(columnName) ;  
                   //设置私有属性可以访问  
                   field.setAccessible(true) ;  
                   //拿到此列对应的值  
                   Object objectValue = rs.getObject(i+1) ;  
                   //给属性赋值  
                   field.set(obj, objectValue) ;  
               }  
               return obj ;  
           }else  
               return null ;  
       } catch (Exception e) {  
           throw new RuntimeException() ;  
       }  
   }  
}


二:Mybatis的DAO层封装


(1)一般先写接口:

public interface DAO {  
   /**  
    * 保存对象  
    *  
    * @param str  
    * @param obj  
    * @return  
    * @throws Exception  
    */  
   public Object save(String str, Object obj) throws Exception;  
   /**  
    * 修改对象  
    *  
    * @param str  
    * @param obj  
    * @return  
    * @throws Exception  
    */  
   public Object update(String str, Object obj) throws Exception;  
   /**  
    * 删除对象  
    *  
    * @param str  
    * @param obj  
    * @return  
    * @throws Exception  
    */  
   public Object delete(String str, Object obj) throws Exception;  
   /**  
    * 查找对象  
    *  
    * @param str  
    * @param obj  
    * @return  
    * @throws Exception  
    */  
   public Object findForObject(String str, Object obj) throws Exception;  
   /**  
    * 查找对象  
    *  
    * @param str  
    * @param obj  
    * @return  
    * @throws Exception  
    */  
   public Object findForList(String str, Object obj) throws Exception;  
   /**  
    * 查找对象封装成Map  
    *  
    * @param s  
    * @param obj  
    * @return  
    * @throws Exception  
    */  
   public Object findForMap(String sql, Object obj, String key, String value) throws Exception;  
}


(2)再写实现层:

@Repository("daoSupport")  
public class DaoSupport implements DAO {  
   @Resource(name = "sqlSessionTemplate")  
   private SqlSessionTemplate sqlSessionTemplate;  
   /**  
    * 保存对象  
    *  
    * @param str  
    * @param obj  
    * @return  
    * @throws Exception  
    */  
   public Object save(String str, Object obj) throws Exception {  
       return sqlSessionTemplate.insert(str, obj);  
   }  
   /**  
    * 批量更新  
    *  
    * @param str  
    * @param obj  
    * @return  
    * @throws Exception  
    */  
   public Object batchSave(String str, List objs) throws Exception {  
       return sqlSessionTemplate.insert(str, objs);  
   }  
   /**  
    * 修改对象  
    *  
    * @param str  
    * @param obj  
    * @return  
    * @throws Exception  
    */  
   public Object update(String str, Object obj) throws Exception {  
       return sqlSessionTemplate.update(str, obj);  
   }  
   /**  
    * 批量更新  
    *  
    * @param str  
    * @param obj  
    * @return  
    * @throws Exception  
    */  
   public void batchUpdate(String str, List objs) throws Exception {  
       SqlSessionFactory sqlSessionFactory = sqlSessionTemplate.getSqlSessionFactory();  
       // 批量执行器  
       SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH, false);  
       try {  
           if (objs != null) {  
               for (int i = 0, size = objs.size(); i < size; i++) {  
                   sqlSession.update(str, objs.get(i));  
               }  
               sqlSession.flushStatements();  
               sqlSession.commit();  
               sqlSession.clearCache();  
           }  
       } finally {  
           sqlSession.close();  
       }  
   }  
   /**  
    * 批量更新  
    *  
    * @param str  
    * @param obj  
    * @return  
    * @throws Exception  
    */  
   public Object batchDelete(String str, List objs) throws Exception {  
       return sqlSessionTemplate.delete(str, objs);  
   }  
   /**  
    * 删除对象  
    *  
    * @param str  
    * @param obj  
    * @return  
    * @throws Exception  
    */  
   public Object delete(String str, Object obj) throws Exception {  
       return sqlSessionTemplate.delete(str, obj);  
   }  
   /**  
    * 查找对象  
    *  
    * @param str  
    * @param obj  
    * @return  
    * @throws Exception  
    */  
   public Object findForObject(String str, Object obj) throws Exception {  
       return sqlSessionTemplate.selectOne(str, obj);  
   }  
   /**  
    * 查找对象  
    *  
    * @param str  
    * @param obj  
    * @return  
    * @throws Exception  
    */  
   public Object findForList(String str, Object obj) throws Exception {  
       return sqlSessionTemplate.selectList(str, obj);  
   }  
   public Object findForMap(String str, Object obj, String key, String value) throws Exception {  
       return sqlSessionTemplate.selectMap(str, obj, key);  
   }  
}




相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
5月前
|
存储 缓存 NoSQL
SpringBoot实用开发篇第四章(整合缓存技术)
SpringBoot实用开发篇第四章(整合缓存技术)
|
5月前
|
XML Java 数据库
Spring5系列学习文章分享---第五篇(事务概念+特性+案例+注解声明式事务管理+参数详解 )
Spring5系列学习文章分享---第五篇(事务概念+特性+案例+注解声明式事务管理+参数详解 )
32 0
|
5月前
|
SQL Java 数据库连接
Spring5系列学习文章分享---第四篇(JdbcTemplate+概念配置+增删改查数据+批量操作 )
Spring5系列学习文章分享---第四篇(JdbcTemplate+概念配置+增删改查数据+批量操作 )
35 0
|
6月前
|
设计模式 Java 机器人
学习笔记之二《SpringBoot3-核心特性》
学习笔记之二《SpringBoot3-核心特性》
143 0
|
6月前
|
缓存 Java uml
SpringBoot2 | Spring IOC 流程中核心扩展接口的12个扩展点源码分析(十一)
SpringBoot2 | Spring IOC 流程中核心扩展接口的12个扩展点源码分析(十一)
109 0
|
XML Java 程序员
【框架源码】SpringBoot核心源码解读之自动配置源码分析
【框架源码】SpringBoot核心源码解读之自动配置源码分析
【框架源码】SpringBoot核心源码解读之自动配置源码分析
|
Java Spring 容器
【框架源码】SpringBoot核心源码解读之启动类源码分析
【框架源码】SpringBoot核心源码解读之启动类源码分析
【框架源码】SpringBoot核心源码解读之启动类源码分析
|
XML 设计模式 Java
【框架源码】手写Spring框架IOC容器核心流程
【框架源码】手写Spring框架IOC容器核心流程
【框架源码】手写Spring框架IOC容器核心流程
|
XML JSON 前端开发
Java开发核心注解总结(一)
Java开发核心注解总结(一)
101 0
|
XML 缓存 NoSQL
JAVA开发常用框架注解与作用
JAVA开发常用框架注解与作用
127 0
下一篇
无影云桌面