`

Spring JdbcTemplate实现通用的泛型dao一:主功能实现

 
阅读更多

Spring JdbcTemplate实现通用的泛型dao一:主功能实现

Spring JdbcTemplate实现通用的泛型dao二:实现自己的名称转换NameHandler 

Spring JdbcTemplate实现通用的泛型dao三:构建动态sql

Spring JdbcTemplate实现通用的泛型dao四:通用自定义转换到JavaBean的RowMapper实现

在项目中一直使用Mybaits,最近想自己搞个小项目,通过对比之后发现mybatis的优势并不是十分明显了,个人小项目倾向于更加简洁的DBUtils。Spring jdbc也实现了DBUtils基本一样的功能,项目中又刚好用到了spring,这当然是不二之选了。

Mybaits采用xml的方式,想要实现通用的dao比较的麻烦,spring jdbc没有类似xml的配置文件,实现一个通用的dao反而简单,参考网上的一些介绍结合自己项目的需求,写了一个算是比较规范的通用dao,这里作下整理。

先来说一下我的通用dao实现的主要几点:

  1. 小项目使用的是mysql,所以是基于mysql数据库,但是差别不大,换数据库的话改几行代码就搞定。
  2. 可以自定义数据库表名、列名到Java类、属性名称的转换。主要是我设计的数据库表中,列名为了防止关键字等各类冲突,都是以下划线”_”开头和分隔的,无法和Java映射实体类的属性名保持一致。
  3. 实现基本的增、删、改、查、分页查询等功能。
  4. 因为没有xml等映射配置文件,所以基于编码和命名的规范性(当然不规范也能支持,但是实现自定义名称处理器将会十分复杂)。所有的数据库列名也好,Java属性名也好,映射都是有一定的规范的,不可能说我数据库列名为user_name,java实体类中映射为tomcat。
  5. 我数据库表的主键名是基于表名再加上“_id”,例如user表主键即为_user_id(所有列以下划线”_”开头)。
  6. 映射的实体类中不能添加数据库表中列不存在的无用字段,这样会使组装的sql语句错误。当然可以用添加注解或其它的方式来判断,但那样会破坏实体类的简洁度。任何情况下不在映射的实体类中添加数据库没有的字段(某些框架的主外键映射除外),如果需要在转换后的VO类中添加,个人认为这是一个好的编码习惯。
  7. 基于spring JdbcTemplate。

下面一步一步的来实现我们的通用dao(在最后有给出完整的代码),接口在这里就不晒了,定义了几个方法的名字而已,先来看一下通用dao实现的定义:

publicabstractclassBaseDaoImpl<T>implementsBaseDao<T>{/** 具体操作的实体类对象 */privateClass<T>       entityClass;/** 名称加工处理器 */privateNameHandler    nameHandler;/** spring jdbcTemplate 对象 */@AutowiredprotectedJdbcTemplate jdbcTemplate;}

把类声明为了abstract类型,因为这个类我们是不需要直接实例化的,我们使用实例化的是继承它的子类。

另外在声明类的时候添加了一个泛型参数<T>,这个T即是需要操作的实体类对象。

entityClass用来保存运行时T的具体类型。

nameHandler即自定义名称处理器。

JdbcTemplate spring的JdbcTemplate 对象,注意这里加了注解@Autowired,并声明为protected作用域,这样继承它的子类在使用spring注解声明bean初始化的时候会帮你自动注入jdbcTemplate。当然你也可以使用xml。

我们先来举一个使用的例子,需要实现一个用户表对应的dao,可以像下面声明:

publicclassUserDaoImplextendsBaseDaoImpl<User>implementsUserDao{}

声明的这个UserDaoImpl不用写任何代码就拥有了对user表操作基本的增删改查功能,可以省略大量的重复工作。回到正题,声明了User这个泛型对象,要对User表进行操作,这就要求在运行时能够动态的得到User这个对象,因为这个User对象根据实现dao的不同是会变的,怎么在运行时得到它呢?我们来看一下public Type getGenericSuperclass()这个方法,doc上说它用来返回表示当前Class 所表示的实体(类、接口、基本类型或 void)的直接超类的Type,好,有了这个,就能拿到我们想要的了,在UserDaoImpl的构造方法中写入如下代码,在类实例化的时候就拿到具体的实体类型:

/**
 * 构造方法,获取运行时的具体实体对象
 */publicBaseDaoImpl(){Type superclass = getClass().getGenericSuperclass();ParameterizedType type =(ParameterizedType) superclass;
    entityClass =(Class<T>) type.getActualTypeArguments()[0];}

基本的工作都做完了,接下来实现业务方法,先来实现相对复杂点的insert,说insert复杂是因为它比其它操作多一了个主键的生成,mysql主键的生成由数据库负责比较简单,主要是保存记录后要返回这个主键以供后面可能需要的其它操作使用,所以不能用简单的调用update或execute方法传入sql完事了,spring提供了KeyHolder的实现,看下面代码:

/**
 * 插入一条记录
 *
 * @param entity
 */@OverridepublicsynchronizedLong insert(T entity){finalSqlContext sqlContext =SqlUtils.buildInsertSql(entity,this.getActualNameHandler());KeyHolder keyHolder =newGeneratedKeyHolder();
    jdbcTemplate.update(newPreparedStatementCreator(){publicPreparedStatement createPreparedStatement(Connection con)throwsSQLException{PreparedStatement ps = con.prepareStatement(sqlContext.getSql().toString(),newString[]{ sqlContext.getPrimaryKey()});int index =0;for(Object param : sqlContext.getParams()){
                index++;
                ps.setObject(index, param);}return ps;}}, keyHolder);return keyHolder.getKey().longValue();}

 

代码很简单,主键将在保存后返回。实现了insert方法,其它的就简单了,下面是整个类的源码:

/**
 * 泛型通用dao实现 依赖于spring jdbc
 *
 * User: liyd
 * Date: 2/12/14
 * Time: 2:34 PM
 */publicabstractclassBaseDaoImpl<T>implementsBaseDao<T>{/** 具体操作的实体类对象 */privateClass<T>       entityClass;/** 名称加工处理器 */privateNameHandler    nameHandler;/** spring jdbcTemplate 对象 */@AutowiredprotectedJdbcTemplate jdbcTemplate;/**
     * 构造方法,获取运行时的具体实体对象
     */publicBaseDaoImpl(){Type superclass = getClass().getGenericSuperclass();ParameterizedType type =(ParameterizedType) superclass;
        entityClass =(Class<T>) type.getActualTypeArguments()[0];}/**
     * 获取实际运行时的名称处理器
     *
     * @return
     */privateNameHandler getActualNameHandler(){if(nameHandler ==null){synchronized(this){if(nameHandler ==null){
                    nameHandler =this.getNameHandler();}}}return nameHandler;}/**
     * 得到名称处理器,子类覆盖此方法实现自己的名称转换处理器
     *
     * @return
     */protectedNameHandler getNameHandler(){returnnewDefaultNameHandler();}/**
     * 插入一条记录
     *
     * @param entity
     */@OverridepublicsynchronizedLong insert(T entity){finalSqlContext sqlContext =SqlUtils.buildInsertSql(entity,this.getActualNameHandler());KeyHolder keyHolder =newGeneratedKeyHolder();
        jdbcTemplate.update(newPreparedStatementCreator(){publicPreparedStatement createPreparedStatement(Connection con)throwsSQLException{PreparedStatement ps = con.prepareStatement(sqlContext.getSql().toString(),newString[]{ sqlContext.getPrimaryKey()});int index =0;for(Object param : sqlContext.getParams()){
                    index++;
                    ps.setObject(index, param);}return ps;}}, keyHolder);return keyHolder.getKey().longValue();}/**
     * 更新记录
     * 
     * @param entity
     */@Overridepublicvoid update(T entity){SqlContext sqlContext =SqlUtils.buildUpdateSql(entity,this.getActualNameHandler());
        jdbcTemplate.update(sqlContext.getSql().toString(), sqlContext.getParams().toArray());}/**
     * 删除记录
     *
     * @param id
     */@Overridepublicvoiddelete(Serializable id){String tableName =this.getActualNameHandler().getTableName(entityClass.getSimpleName());String primaryName =this.getNameHandler().getPrimaryName(entityClass.getSimpleName());String sql ="DELETE FROM "+ tableName +" WHERE "+ primaryName +" = ?";
        jdbcTemplate.update(sql, id);}/**
     * 删除所有记录
     */@Overridepublicvoid deleteAll(){String tableName =this.getActualNameHandler().getTableName(entityClass.getSimpleName());String sql =" TRUNCATE TABLE "+ tableName;
        jdbcTemplate.execute(sql);}/**
     * 得到记录
     *
     * @param id
     * @return
     */@Overridepublic T getById(Serializable id){String tableName =this.getNameHandler().getTableName(entityClass.getSimpleName());String primaryName =this.getNameHandler().getPrimaryName(entityClass.getSimpleName());String sql ="SELECT * FROM "+ tableName +" WHERE "+ primaryName +" = ?";return(T) jdbcTemplate.query(sql,newDefaultRowMapper(entityClass,this.getActualNameHandler()), id).get(0);}/**
     * 查询所有记录
     * 
     * @return
     */@OverridepublicList<T> findAll(){String sql ="SELECT * FROM "+this.getActualNameHandler().getTableName(entityClass.getSimpleName());return(List<T>) jdbcTemplate.query(sql,newDefaultRowMapper(entityClass,this.getActualNameHandler()));}/**
     * 查询记录数
     * 
     * @param entity
     * @return
     */publicint queryCount(T entity){String tableName =this.getActualNameHandler().getTableName(entityClass.getSimpleName());StringBuilder countSql =newStringBuilder("select count(*) from ");
        countSql.append(tableName);SqlContext sqlContext =SqlUtils.buildQueryCondition(entity,this.getActualNameHandler());if(sqlContext.getSql().length()>0){
            countSql.append(" where ");
            countSql.append(sqlContext.getSql());}return jdbcTemplate.queryForInt(countSql.toString(), sqlContext.getParams().toArray());}/**
     * 查询分页列表
     * 
     * @param entity
     * @return
     */publicPager queryPageList(T entity){Pager pager =newPager();PagingOrder pagingOrder =(PagingOrder) entity;
        pager.setCurPage(pagingOrder.getCurPage());
        pager.setItemsPerPage(pagingOrder.getItemsPerPage());String tableName =this.getActualNameHandler().getTableName(entityClass.getSimpleName());String primaryName =this.getActualNameHandler().getPrimaryName(entityClass.getSimpleName());StringBuilder querySql =newStringBuilder("select * from ");StringBuilder countSql =newStringBuilder("select count(*) from ");
        querySql.append(tableName);
        countSql.append(tableName);//不调用queryCount方法,条件共同组装一次,减少反射获取的次数SqlContext sqlContext =SqlUtils.buildQueryCondition(entity,this.getActualNameHandler());if(sqlContext.getSql().length()>0){
            querySql.append(" where ");
            countSql.append(" where ");
            querySql.append(sqlContext.getSql());
            countSql.append(sqlContext.getSql());}
        querySql.append(" order by ");
        querySql.append(primaryName);
        querySql.append(" desc ");
        querySql.append("limit ?,?");List<Object> queryParams =newArrayList<Object>(sqlContext.getParams());
        queryParams.add(pager.getBeginIndex());
        queryParams.add(pager.getItemsPerPage());List<T> list =(List<T>) jdbcTemplate.query(querySql.toString(), queryParams.toArray(),newDefaultRowMapper(entityClass,this.getActualNameHandler()));int totalCount = jdbcTemplate.queryForInt(countSql.toString(), sqlContext.getParams().toArray());
        pager.setList(list);
        pager.setItems(totalCount);return pager;}}

 

这样,一个通用dao的实现思路已经清晰给出了。可能你注意到了里面的几个细节部分的几个方法,

SqlUtils.buildUpdateSql(entity, this.getActualNameHandler());

构建动态的sql,getActualNameHandler获取具体的名称处理器实现属性名到列名的转换。

(List<T>) jdbcTemplate.query(sql, new DefaultRowMapper(entityClass, this.getActualNameHandler()));

其中DefaultRowMapper是自定义实现的数据到实体对象的转换。

篇幅所限,具体见其专门的介绍。

分享到:
评论
1 楼 xurichusheng 2015-01-15  
有个类 NameUtils 是在哪儿声明的呢?

相关推荐

    JdbcTemplate通用泛型Dao实现

    本文将深入探讨`JdbcTemplate`通用泛型Dao实现的相关知识点,帮助开发者更好地理解和应用这一技术。 首先,让我们了解什么是`JdbcTemplate`。它是Spring框架的一部分,用于处理SQL操作。`JdbcTemplate`提供了一组...

    Hibernate泛型DAO(结合spring模板支持)

    本篇文章将探讨如何使用Hibernate实现泛型DAO,并结合Spring模板来增强其功能。 泛型DAO是一种设计模式,它通过定义一个通用的DAO接口或抽象类,可以适用于不同的实体类,减少了重复的代码。这种模式的核心在于利用...

    JDBCTemplate+JavaPOJO实现通用DAO

    在这个"JDBCTemplate+JavaPOJO实现通用DAO"的项目中,我们将探讨如何利用这两者构建一个通用的DAO层。 首先,Java POJO(Plain Old Java Object)是指那些没有特殊约束的简单Java对象,通常用于表示数据库中的实体...

    使用Spring的JdbcTemplate实现分页功能

    使用Spring的JdbcTemplate实现分页功能

    java 基于泛型与反射的通用 DAO

    综上所述,这个项目展示了如何利用Java的泛型和反射技术实现一个通用的DAO,使得数据库操作更加灵活和易于维护。泛型确保了类型安全,而反射则提供了运行时的动态行为。这种设计模式在实际开发中非常常见,尤其是在...

    基于注解的Spring JdbcTemplate

    Spring JDBC模絫提供了一种简洁的方式来处理数据库操作,而`Spring JdbcTemplate`是这个模絫的核心组件。本教程将深入探讨如何使用基于注解的Spring JdbcTemplate进行数据库操作,特别适合初学者入门学习。 ### 1. ...

    Java Web程序运用中泛型DAO的作用.zip

    在实际的Java Web应用中,我们可以结合Spring框架的Hibernate或JPA支持,进一步简化泛型DAO的实现,利用Spring的模板类如JdbcTemplate、HibernateTemplate等,自动处理SQL执行和结果映射。 总的来说,泛型DAO在Java...

    spring-jdbcTemplate实例工程

    - **配置JdbcTemplate**:首先,需要在Spring配置文件中声明一个JdbcTemplate bean,并注入DataSource。 - **执行SQL**:调用JdbcTemplate的execute()方法执行SQL,对于查询操作,可以使用query()方法,传入SQL、...

    SpringJdbcTemplate封装工具类

    SpringJdbcTemplate是Spring框架中用于简化Java数据库访问的工具,它是Spring JDBC模块的核心。这个封装工具类的出现是为了提供一种更简洁、易于使用的接口来执行SQL操作,减轻开发者处理数据库连接、事务管理以及...

    Spring JdbcTemplate调用Oracle存储过程实现CRUD

    使用 Spring JdbcTemplate 调用 Oracle 存储过程实现 CRUD 在本文中,我们将讨论如何使用 Spring JdbcTemplate 调用 Oracle 存储过程来实现 CRUD(Create、Read、Update、Delete)操作。我们将首先编写 Oracle 存储...

    模仿spring jdbcTemplate的实现

    模仿spring jdbcTemplate的粗略实现,只有很小的参考价值,如果是java初学者可以使用这个封装好的工具进行数据库操作,只需要在db.properties里配置好driver,url等信息

    Spring JDBCTemplate连接池jar包

    4. `spring-tx-5.0.0.RELEASE.jar`:提供了事务管理功能,可以配合JDBCTemplate进行事务的声明式或编程式管理。 5. `commons-logging-1.2.jar`:Apache Commons Logging库,是Spring的日志适配器,允许我们灵活地...

    strut2+spring+springjdbctemplate做的简易登录系统

    总的来说,这个简易登录系统结合了Struts2的MVC架构、Spring的依赖注入和事务管理以及Spring JDBC Template的数据库操作,实现了用户登录功能。通过这样的组合,开发者可以更高效地构建和维护Java Web应用。

    Spring JdbcTemplate

    **Spring JdbcTemplate**是Spring框架中的一个核心组件,主要用于简化Java数据库访问。它提供了一种模板化的方式来执行SQL语句,使得开发人员可以避免编写大量的重复代码,专注于业务逻辑,而不是底层的数据库交互...

    4.Spring中的JdbcTemplate,Spring中的的事务,

    JdbcTemplate是Spring框架提供的一种用于简化JDBC编程的对象。通过封装原生的JDBC API,JdbcTemplate不仅提高了代码的可读性和可维护性,还帮助开发者避免了许多常见的错误,比如资源关闭、SQL注入等问题。 Spring...

    Spring JdbcTemplate 常用方法整理

    Spring的JdbcTemplate是Spring框架中用于简化数据库操作的工具类,它是基于JDBC但又抽象出了一层,避免了直接与数据库驱动API交互,从而提高了代码的可读性和可维护性。本文将深入探讨Spring JdbcTemplate的常用方法...

    基于 Java+Mysql 实现的图书管理系统( Spring+Spring MVC+JdbcTemplate)

    【作品名称】:基于 Java+Mysql 实现的图书管理系统( Spring+Spring MVC+JdbcTemplate) 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项...

    Spring JdbcTemplate例子

    Spring JdbcTemplate是Spring框架中的一个核心组件,主要用来简化数据库操作。它提供了一种模板方法设计模式,将SQL语句的执行与结果处理进行了抽象,使得开发者可以更加专注于业务逻辑,而无需关心底层数据访问的...

    spring的jdbctemplate的crud的基类dao

    通过这种方式,`BaseDaoImpl` 类为所有继承它的DAO提供了一个通用的CRUD操作基础,具体的业务逻辑可以在继承这个基类的DAO中实现,只需覆盖或扩展这些方法即可。这种方式提高了代码的可重用性,降低了重复的工作量,...

    Druid数据库连接池的SpringJDBCTemplate所需的jar包

    Druid数据库连接池的SpringJDBCTemplate所需的jar包,Druid数据库连接池的SpringJDBCTemplate所需的jar包,Druid数据库连接池的SpringJDBCTemplate所需的jar包,Druid数据库连接池的SpringJDBCTemplate所需的jar包,...

Global site tag (gtag.js) - Google Analytics