Cook JDBC with SpringFramework

        我们的目标是希望在任何使用JDBC的场合都能够利用SpringFramework的JDBC  Support  Module,同时尽可能少地引入不必要的元素。因此,我们假定不使用J2EE环境提供的任何服务,也不使用SpringFramework的IoC容器和AOP两大特性。

        首先,我们需要的自然是一个DataSource。在非J2EE环境下,可以使用Jakarta的commons-dbcp来得到一个DataSource的实例。我们选择使用SharedPoolDataSource,它提供了一个close()方法,在程序结束前调用它可以关闭所有的Connection,释放相关的资源。

        接着,将spring-core.jar和spring-dao.jar置入CLASSPATH。事实上,我们将要用到的class几乎全部都在spring-dao.jar中,之所以需要spring-core.jar是因为NestedRuntimeException,所有JDBC  Support  Module中的异常都直接或间接继承自这个Runtime  Exception。由此也可以看出,我们只是在受控制的情况下引入了SpringFramework的一小部分而已。

     下面,我们就可以开始逐步设置和组装我们的基础设施。

org.springframework.jdbc.core.JdbcTemplate

     JdbcTemplate是整个package的核心,所有的JDBC调用流程都通过它来完成,开发者只需要实现对应的callback接口即可。JdbcTemplate是无状态且线程安全的,也就是说在整个系统中只需要创建一个实例就够了。创建它的时候需要提供DataSource作为参数。

   JdbcTemplate  jdbcTemplate  =  new  JdbcTemplate(dataSource);
   jdbcTemplate.afterPropertiesSet();

     afterPropertiesSet()方法是对InitializingBean接口的实现,如果实例是由IoC容器管理的,则容器会自动调用。由于我们并没有使用IoC容器,所以需要在创建实例后主动调用该方法。

org.springframework.transaction.support.TransactionTemplate

     TransactionTemplate帮助我们以编程的方式实现事务控制。同样的,开发者也是通过实现callback接口来使用它。TransactionTemplate也是无状态且线程安全的。创建TransactionTemplate的实例需要提供一个PlatformTransactionManager的实例,在SpringFramework中有多种PlatformTransactionManager的实现类,提供多种事务控制的途径。基于前面设定的限制,我们选择DataSourceTransactionManager。




   PlatformTransactionManager  platformTransactionManager  =  
       new  DataSourceTransactionManager(dataSource);
   TransactionTemplate  transactionTemplate  =  
       new  TransactionTemplate(platformTransactionManager);
   transactionTemplate.afterPropertiesSet();

org.springframework.jdbc.support.incrementer.DataFieldMaxValueIncrementer

     在数据库中插入数据的时候,需要获得唯一的Long或Integer类型的值做为主键。DataFieldMaxValueIncrementer提供了这样一个途径,而具体的实现方法则因各种数据库系统而异。简单地说,如果数据库系统本身提供了Sequences(例如Oracle),则直接从sequences取得所需的序列值,如果数据库系统不支持Sequences(例如MySQL),则通过一个单独的Table来保存和产生新的序列值。每个DataFieldMaxValueIncrementer的实例都需要有一个对应的Sequences或者Table,换句话说,开发者要选择是整个系统共用同一个Incrementer实例,还是对应每个Table使用各自专有的Incrementer实例。目前SpringFramework已经提供了针对Oracle、DB2、PostgreSQL、MySQL,HSQL五种数据库的实现,支持从超重量级直到超轻量级的常见数据库系统,而且,要自己编写针对其它数据库系统的实现也并非难事。在例子中我们选择使用HSQL数据库,创建一个HsqlMaxValueIncrementer的实例需要提供DataSource、table  name、column  name。

   HsqlMaxValueIncrementer  incrementer  =  new  HsqlMaxValueIncrementer(dataSource,
         "id_sequence",  "value");
   incrementer.afterPropertiesSet();

     基础设施准备好了之后,就可以在上面进行DAO的实现了,前面已经提到了开发者是通过实现callback接口来使用JdbcTemplate的,现在让我们来逐个尝试。

     Insert、Update、Delete三种情况都不需要返回结果给调用者,因此可以使用JdbcTemplate的update()方法,该方法有多个重载的版本,可以根据实际情况选择一个合适的。由于数据库系统的原因,我无法测试对BLOB和CLOB的操作,但是从文档来看,相关的支持应该是满足需要的。

         long  id  =  incrementer.nextLongValue();
         user.setId(id);
         String  sql  =  "INSERT  INTO  users  VALUES  (?,?,?,?);";
         Object[]  params  =  new  Object[]  {  new  Long(id),  user.getUsername(),
                 user.getPassword(),  new  Boolean(user.isEnabled())  };
         jdbcTemplate.update(sql,  params);

     对于Query,则是使用JdbcTemplate的query()方法,同样提供了多个重载的版本。通常要先实现一个RowMapper,能够将ResultSet中的一条记录取出来,填充到一个对象中。我们可以将它设计为一个内部类,同时它的实例也是线程安全的。

private  class  UserRowMapper  implements  RowMapper
{
     public  Object  mapRow(ResultSet  resultSet,  int  row)  throws  SQLException
     {
           User  user  =  new  User();
           user.setId(resultSet.getLong("id"));
           user.setUsername(resultSet.getString("username"));
           user.setPassword(resultSet.getString("password"));
           user.setEnabled(resultSet.getBoolean("enabled"));
           return  user;
     }
}

         String  sql  =  "SELECT  *  FROM  users;";
         RowMapper  mapper  =  new  UserRowMapper();
         RowMapperResultReader  reader  =  new  RowMapperResultReader(mapper);
         List  users  =  jdbcTemplate.query(sql,  reader);
         return  users;

     数据库操作自然离不开事务控制,使用TransactionTemplate很简单,只需要调用execute()方法即可。当然前提是你实现了TransactionCallback接口,并且在doInTransaction()方法里进行各种数据库操作。于是这一组操作就会作为一个事务提交,一旦出现任何异常,则相应地进行事务回滚。

     transactionTemplate.execute(createUser);

   public  Object  doInTransaction(TransactionStatus  status)
   {
       try
       {
           userDao.insertUser(user);
           authorityDao.updateAuthority(user,  auths);
       }
       catch  (Exception  exception)
       {
           status.setRollbackOnly();
           log.debug(exception.getCause(),  exception);
       }
       return  null;
   }


   以上,就是借助SpringFramework  JDBC  Support的DAO实现方式。我们可以将最初设定的限制条件放宽一些,假定我们处于J2EE环境下,那么DataSource的实例可以通过JNDI直接从J2EE容器获得,同时也可以选择通过JTA进行事务控制。假定我们使用SpringFramework的IoC容器,那么所有前面提到的对象都可以交给IoC容器中进行设置和组装,以获得更简洁、更灵活的代码实现。

     我还漏了一点——在前面的代码中看不出来——SpringFramework对SQLException的重新包装。SQLException所携带的信息几乎都是通过其中的error  code来传递的,而本身类的层次结构扁平,我们只好不分青红皂白全都catch住,然后再根据error  code决定是否应该进行一些异常处理。而SpringFramework的异常类层次结构很丰富,我们可以充分利用try  catch机制仅catch那些我们想要处理的异常,这又使我们的代码倾向于简洁。

     结论:在一个典型的项目中,如果我们由于这样或那样的原因决定不使用EJB、Hibernate、iBatis等等等等,而打算亲自操刀烹调JDBC时,同样有充分的理由使用SpringFramework。我们只需要付出很少的学习成本,就能让我们的DAOs更可靠、更灵活、更一针见血。

Tom Cook乘法是由一位叫做汤姆·库克(Tom Cook)的数学家发明的一种新颖的乘法方法。这种方法是为了简化计算和记忆乘法表而设计的。 在传统的乘法方法中,我们需要通过竖式计算来获得两个数的乘积。但是,这种方法有时候会让人感到复杂和困惑,尤其是在计算大数的乘积时。 而Tom Cook乘法则采用了一种更简单的方式。首先,我们将两个数分别写在两行的开头,并不断地将它们除以2,直到其中一个数变为1为止。然后,我们将另一个数一直除以2,并将商写在每行的右边。最后,我们将两行的右边相应的商相加,得到的结果就是原始两个数的乘积。 这种方法的原理基于二进制,因为二进制是计算机中最基本的数字系统。Tom Cook乘法实质上是将十进制转换为二进制,通过对各个二进制位的运算得到乘积。 Tom Cook乘法的最大优势在于它简化了乘法计算的过程,特别是在大数乘法中。相比传统的竖式计算,Tom Cook乘法只需要进行一次除以2的运算和一次加法运算,大大减少了计算步骤和记忆乘法表的困难。 然而,Tom Cook乘法并非在所有场景下都适用。它主要适用于大数乘法,尤其是计算机科学中的二进制运算。对于一般的小数乘法,传统的竖式计算仍然是更常用和直观的方法。 总的来说,Tom Cook乘法是一种创新的乘法方法,通过简化计算和记忆乘法表,使乘法运算更加易于理解和实施。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值