Spring 之 ORM (JdbcTemplate)

 JdbcTemplate 简介

       

         spring 提供了不同持久层的技术的支持! ORM持久化技术  主要包含: JDBC,Hibernate,IBatis(MyBatis),JPA

       对应的模板类如下:
          ①JDBC               org.springframework.jdbc.core.JdbcTemplate
          ②Hibernate           org.springframework.orm.hibernate4.HibernateTemplate
          ③ IBatis(MyBatis)    org.springframework.orm.ibatis.SqlMapClientTemplate
          ④ JPA                    org.springframwork.orm.jpa.JpaTemplate

      其中 JdbcTempate 简称JDBC 编程!

  spring jdbc 框架   

      Srping  JDBC 框架(Spring-jdbc-x.x.x.x.RELEASE.jar) 由4个部分组成

              ① core 包: 提供了JDBC 模板类,JdbcTemplate 是core包的核心类!
              ② dataSource 包: 提供简化访问JDBC 数据源的工具类!
                    -- 并提供一些DataSource 简单实现类,从而使用DataSource 获取连接并得到Spring 的事务支持!
              ③ object 包,提供关系型数据的对象表现形式,如MappingSqlQuery,SqlUpdate,SqlCall,SqlFunction 等
              ④ support 包, 提供将JDBC 异常转换为DAO 非检查异常的转换类和一些工具类!

   

Jdbc 编程快速入门  

          第一步:maven 依赖 

<!-- spring 核心 -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>4.3.9.RELEASE</version>
</dependency>
<!-- Spring AOP 所需 依赖 -->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.8.9</version>
</dependency>
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.2.4</version>
</dependency>
 <!-- Spring Dao -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>4.3.9.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
    <version>4.3.9.RELEASE</version>
</dependency>

<!-- mysql驱动包 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.29</version>
</dependency>
      第二步: 配置连接/并执行SQL        

public  void testNoConfigTemplate(){
    //获取数据源
    DriverManagerDataSource dataSource = new DriverManagerDataSource();

    dataSource.setDriverClassName("org.gjt.mm.mysql.Driver");
    dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/test");
    dataSource.setUsername("root");
    dataSource.setPassword("root99999");
    JdbcTemplate template = new JdbcTemplate(dataSource);
    template.execute("create table t_user(id INT ,NAME VARCHAR (2))");
}

       或 xml 配置

<!-- 第一种 Spring 内置数据源 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="org.gjt.mm.mysql.Driver"/>
    <property name="url" value="jdbc:mysql://127.0.0.1:3306/test"/>
    <property name="username" value="root"/>
    <property name="password" value="root99999"/>

</bean>

<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="dataSource"/>
</bean>
@Autowired
private  JdbcTemplate template;

@Test
public  void testXmlTemplate(){
    template.execute("INSERT INTO  t_user VALUES (2,'王wu')");
}       


Spring 连接池

      Spring 自带 DriverManagerDataSource 连接池

<!-- 第一种 Spring 内置数据源 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="org.gjt.mm.mysql.Driver"/>
    <property name="url" value="jdbc:mysql://127.0.0.1:3306/test"/>
    <property name="username" value="root"/>
    <property name="password" value="root99999"/>

</bean>
            

       DBCP数据源

          DBCP(DataBase connection pool),数据库连接池。是 apache 上的一个 java 连接池项目,也是 tomcat 使用的连接池组件。单独使用dbcp需要3个包:common-dbcp.jar,common-pool.jar,common-collections.jar由于建立数据库连接是一个非常耗时耗资源的行为,所以通过连接池预先同数据库建立一些连接,放在内存中,应用程序需要建立数据库连接时直接到连接池中申请一个就行,用完后再放回去。但是 dbcp没有自动的去回收空闲连接的功能! 

   commons-dbcp现在分成了3个大版本,不同的版本要求的JDK不同:
  DBCP now comes in three different versions to support different versions of JDBC. Here is how it works:
  DBCP 2 compiles and runs under Java 7 only (JDBC 4.1)
  DBCP 1.4 compiles and runs under Java 6 only (JDBC 4)
  DBCP 1.3 compiles and runs under Java 1.4-5 only (JDBC 3)

            对应的maven依赖如下: 

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-dbcp2</artifactId>
    <version>2.2.0</version>
</dependency>
            xml 文件配置-- 具体配置 参考 << DBCP2配置详细说明 > >

<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource"
      destroy-method="close">
    <property name="driverClassName" value="org.gjt.mm.mysql.Driver" />
    <property name="url" value="jdbc:mysql://127.0.0.1:3306/test" />
    <property name="username" value="root" />
    <property name="password" value="password" />
    <property name="initialSize" value="10" /><!-- 初始化连接:连接池启动时创建的初始化连接数量 -->
    <property name="maxTotal" value="100" /> <!-- 可以在这个池中同一时刻被分配的有效连接数的最大值,如设置为负数,则不限制 -->
    <property name="maxIdle" value="100" />  <!-- 最大空闲连接数-->
    <property name="maxWaitMillis" value="-1" /> <!-- 从连接池获取一个连接时,最大的等待时间-->
</bean>
  C3P0 数据源

 C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate,Spring等。并且 c3p0有自动回收空闲连接功能!

       对应的maven依赖如下:

<dependency>
    <groupId>com.mchange</groupId>
    <artifactId>c3p0</artifactId>
    <version>0.9.5.2</version>
</dependency>

xml 具体配置 --请参考c3p0详细配置>>

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">

    <property name="driverClass" value="${jdbc.driverClass}" />

    <property name="jdbcUrl" value="${jdbc.jdbcUrl}" />

    <property name="user" value="${jdbc.user}" />

    <property name="password" value="${jdbc.password}" />

    <property name="minPoolSize" value="${jdbc.miniPoolSize}" />

    <property name="maxPoolSize" value="${jdbc.maxPoolSize}"/>

    <property name="initialPoolSize" value="${jdbc.initialPoolSize}"/>

    <property name="maxIdleTime" value="${jdbc.maxIdleTime}"/>

    <property name="acquireIncrement" value="${jdbc.acquireIncrement}"/>

    <property name="acquireRetryAttempts" value="${jdbc.acquireRetryAttempts}"/>

    <property name="acquireRetryDelay" value="${jdbc.acquireRetryDelay}"/>

    <property name="testConnectionOnCheckin" value="${jdbc.testConnectionOnCheckin}"/>

    <property name="automaticTestTable" value="${jdbc.automaticTestTable}"/>

    <property name="idleConnectionTestPeriod" value="${jdbc.idleConnectionTestPeriod}"/>

    <property name="checkoutTimeout" value="${jdbc.checkoutTimeout}"/>

</bean>
druid

Druid首先是一个数据库连接池。Druid是目前最好的数据库连接池,在功能、性能、扩展性方面,都超过其他数据库连接池,包括DBCP、C3P0、BoneCP、Proxool、JBoss DataSource。

Druid是一个JDBC组件,它包括三个部分:

支持所有JDBC兼容的数据库,包括Oracle、MySql、Derby、Postgresql、SQL Server、H2等等。Druid针对Oracle和MySql做了特别优化,比如Oracle的PS Cache内存占用优化,MySql的ping检测优化。Druid提供了MySql、Oracle、Postgresql、SQL-92的SQL的完整支持,这是一个手写的高性能SQL Parser,支持Visitor模式,使得分析SQL的抽象语法树很方便。简单SQL语句用时10微秒以内,复杂SQL用时30微秒。通过Druid提供的SQL Parser可以在JDBC层拦截SQL做相应处理,比如说分库分表、审计等。Druid防御SQL注入攻击的WallFilter就是通过Druid的SQL Parser分析语义实现的。

 对应的maven依赖

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.6</version>
</dependency>
xml 具体配置-- 具体配置请参考 <Druid 详细配置>

<!-- 加载配置文件 -->
<context:property-placeholder location="classpath:db.properties" />
<!-- 使用jdbc驱动数据源 -->
<bean id="dataSource"
      class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
    <!-- 数据库基本信息配置 -->
    <property name = "url" value = "${jdbc.url}" />
    <property name = "username" value = "${jdbc.username}" />
    <property name = "password" value = "${jdbc.password}" />
    <property name = "driverClassName" value = "${jdbc.driverClassName}" />
    <property name = "filters" value = "${jdbc.filters}" />
    <!-- 最大并发连接数 -->
    <property name = "maxActive" value = "${jdbc.maxActive}" />
    <!-- 初始化连接数量 -->
    <property name = "initialSize" value = "${jdbc.initialSize}" />
    <!-- 配置获取连接等待超时的时间 -->
    <property name = "maxWait" value = "${jdbc.maxWait}" />
    <!-- 最小空闲连接数 -->
    <property name = "minIdle" value = "${jdbc.minIdle}" />
    <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
    <property name = "timeBetweenEvictionRunsMillis" value ="${jdbc.timeBetweenEvictionRunsMillis}" />
    <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
    <property name = "minEvictableIdleTimeMillis" value ="${jdbc.minEvictableIdleTimeMillis}" />
    <!-- 用来检测连接是否有效的sql,要求是一个查询语句 -->
    <property name = "validationQuery" value = "${jdbc.validationQuery}" />
    <!-- 申请连接的时候检测 -->
    <property name = "testWhileIdle" value = "${jdbc.testWhileIdle}" />
    <!-- 申请连接时执行validationQuery检测连接是否有效,配置为true会降低性能 -->
    <property name = "testOnBorrow" value = "${jdbc.testOnBorrow}" />
    <!-- 归还连接时执行validationQuery检测连接是否有效,配置为true会降低性能 -->
    <property name = "testOnReturn" value = "${jdbc.testOnReturn}" />
    <!-- 超过时间限制是否回收 -->
    <property name = "removeAbandoned" value = "${jdbc.removeAbandoned}" />
    <!-- 超过时间限制多长 -->
    <property name = "removeAbandonedTimeout" value ="${jdbc.removeAbandonedTimeout}" />
    <!-- 关闭 abanded 连接时输出错误日志 -->
    <property name = "logAbandoned" value = "${jdbc.logAbandoned}" />

</bean>

基于JdbcTemplate 的CRUD

     一. DAO 注入 Template

               为了方便DAO 中注入JdbcTemplate ,Spring 为每一个持久化技术都提供了支持类

     所以,DAO 注入Template 只需继承对应的Support 类,便会自动注入模板的方法

public class CustomerDao extends JdbcDaoSupport {

    public void createTable(){
        String sql="create table customer(id INT ,NAME VARCHAR (20),age INT )";
        super.getJdbcTemplate().execute(sql);
    }
   二.基于JdbcTemplate 实现增,删,改,查


方法名称说明
void execute(String sql)可以用于任何sql语句
int update(String sql,Object..args)执行DML语句,如UPDATE、INSERT、DELETE,args是其对应的参数
List<T> query(String sql,RowMapper<T> rowMapper)执行sql查询语句,并根据RowMapper具体的实现类返回结果类型
int queryForInt(String sql)queryForXXX(),XXX代表结果类型,执行sql查询语句,返回结果是整数
T queryForObject(String sql,Object[] args,RowMapper<T> rowMapper)根据sql语句和参数返回结果对象
List<Map<String,Object>> queryForList(String sql,Object..args)根据sql语句和参数返回结果列表,每个Map的key是列名,value是该列对应的数据

 采用update 实现 增,删,改

/**
 * 添加用户
 * @param customer
 */
public void sava(Customer customer){
    String sql=" insert into customer values(?,?,?)";
    super.getJdbcTemplate().update(sql,customer.getId(),customer.getName(),customer.getAge());
}

/**
 * 更新用户信息
 * @param customer
 */
public void update(Customer customer){
    String sql="update customer set name=?,age=? where id=?";
    super.getJdbcTemplate().update(sql,customer.getName(),customer.getAge(),customer.getId());
}

/**
 * 删除用户
 * @param customer
 */
public void delete(Customer customer){
    String sql="DELETE  FROM  customer where id=?";
    super.getJdbcTemplate().update(sql,customer.getId());

}

  三.查询

       基于JdbcTemplate 实现简单返回结果查询       

/**
 * 查询返回简单的对象的名称
 * @param id
 * @return
 */
public String findCustomerName(Integer id){
    String sql="select name from customer where id=?";
    return  super.getJdbcTemplate().queryForObject(sql,String.class,id);
}

    基于 JdbcTemplate 实现复杂对象 需要使用RowMapper 接口

             RowMapper 即一个接口,实现将表中的一行数据转换为一个对象!(如果列名和属性名一致,sping 3 使用ParameterizedBeanPropertyRowMapper 进行自动封装,如果是 Spring4 需要使用BeanPropertyRowMapper 进行自动封装! 如果列名和属性名 不一致需要进行自定义封装!
 )

**
 * 查询具体某个用户信息
 * @param id
 * @return
 */
public  Customer findCustomerById(Integer id){
    String sql="select * from customer where id =?";
    return  super.getJdbcTemplate().queryForObject(sql, BeanPropertyRowMapper.newInstance(Customer.class),id);
}

/**
 * 查询所有的用户信息
 * @return
 */
public List<Customer> findCustomerAll(){
    String sql="select * from customer";
    return  super.getJdbcTemplate().query(sql,BeanPropertyRowMapper.newInstance(Customer.class));
}
        

JdbcTemplate支持对存储过程的调用

Spring JdbcTemplate支持对存储过程的调用(JDK最低1.5版本),JdbcTemplate支持的存储过程回调类如下:

——CallableStatementCreator:

通过回调获取JdbcTemplate提供的Connection,由用户使用该Connection创建相关的CallableStatement

——CallableStatementCallback:

通过回调获取JdbcTemplate提供的CallableStatement,用户可以再CallableStatement执行任何操作


1)执行无返回值的存储过程:

[java]  view plain  copy
  1. package com.wzj.test;  
  2.   
  3.   
  4. import org.springframework.jdbc.core.JdbcTemplate;  
  5.   
  6.   
  7. public class Demo{  
  8.     private JdbcTemplate jdbcTemplate;  
  9.     //省略get、set  
  10.       
  11.     public void test(){  
  12.         jdbcTemplate.execute("{call procedureName(param,param...)}");  
  13.     }  
  14. }  

(2)执行返回非结果集的存储过程:

创建存储过程:
[sql]  view plain  copy
  1. create or replace procedure get_user_name(id in varchar2,username out varchar2) is  
  2. begin  
  3.     select username from User where userid=id;  
  4. end  
调用:
[java]  view plain  copy
  1. public void test(){  
  2.     jdbcTemplate.execute(new CallableStatementCreator() {  
  3.         @Override  
  4.         public CallableStatement createCallableStatement(Connection con)  
  5.                 throws SQLException {  
  6.             String userid="22";  
  7.             //创建对象  
  8.             CallableStatement cs=con.prepareCall("call get_user_name(?,?)");  
  9.             //设置参数  
  10.             cs.setString(1, userid);  
  11.             //设置输出参数  
  12.             cs.registerOutParameter(2, OracleTypes.VARCHAR);  
  13.             return cs;  
  14.         }  
  15.     }, new CallableStatementCallback() {  
  16.         @Override  
  17.         public Object doInCallableStatement(CallableStatement cs)  
  18.                 throws SQLException, DataAccessException {  
  19.             //执行存储过程  
  20.             cs.execute();  
  21.             //获取输出参数  
  22.             return cs.getString(2);  
  23.         }  
  24.     });  
  25. }  

(3)执行返回结果集的存储过程:

①建立程序包:
[sql]  view plain  copy
  1. create or replace package userpackage as   
  2.   type user_cursor is ref cursor;   
  3. end userpackage;   
②创建存储过程:
[sql]  view plain  copy
  1. create or replace procedure get_user(user_cursor out userpackage.user_cursor) is   
  2. begin   
  3.      open user_cursor for select * from User;   
  4. end;   
③调用:
[java]  view plain  copy
  1. public void test() {   
  2.     List userList = (List) jdbcTemplate.execute(   
  3.             new CallableStatementCreator() {   
  4.                 public CallableStatement createCallableStatement(Connection con) throws SQLException {   
  5.                     CallableStatement cs = con.prepareCall("{call get_user(?)}");   
  6.                     cs.registerOutParameter(1, OracleTypes.CURSOR);// 注册输出参数的类型   
  7.                     return cs;   
  8.                 }   
  9.             }, new CallableStatementCallback() {   
  10.                 public Object doInCallableStatement(CallableStatement cs) throws SQLException,DataAccessException {   
  11.                     List userMap = new ArrayList();   
  12.                     cs.execute();   
  13.                     ResultSet rs = (ResultSet) cs.getObject(1);// 获取游标一行的值   
  14.                     while (rs.next()) {// 转换每行的返回值到Map中   
  15.                         Map rowMap = new HashMap();   
  16.                         rowMap.put("userid", rs.getString("userid"));   
  17.                         rowMap.put("username", rs.getString("username"));   
  18.                         userMap.add(rowMap);   
  19.                     }   
  20.                     rs.close();   
  21.                     return userMap;   
  22.                 }   
  23.             });   
  24.     for (int i = 0; i < userList.size(); i++) {   
  25.         Map rowMap = (Map) userList.get(i);   
  26.         String id = rowMap.get("userid").toString();   
  27.         String name = rowMap.get("username").toString();   
  28.         System.out.println("usreid=" + id + ";username=" + name);   
  29.     }   
  30. }   

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
一、SBORM 介绍 1、目前只考虑支持 mysql; 2、基于spring jdbc的上层封装,底层jdbc操作基于JdbcTemplate,对于使用spring jdbc的人会有一点价值,比较简洁的封装可以节省很多重复劳动,具体节省多少可以看看example; 3、实现一套简单的ORM(直接使用spring rowmapper,insert自己实现),可以基于对象进行crud和相对复杂(感觉比hibernate强大一点)的sql操作; 4、基于对象指定查询的字段,大部分时候可以忘掉表结构进行业务开发; 5、支持简单的数据库路由,读写分离(半自动,需要指定取writer还是reader,默认规则reader采用随机的方式,当然也可以手动指定); 6、支持简单的分表,主要是针对一定规则的分表,比如百分表、千分表,也可以自己指定分表后缀; 7、简单的单表查询(比如所有条件是and或者or结构),基本实现0sql代码编写(类似HibernateTemplate selectByExample、findByCriteria、find等方法); 8、简单的单表排序支持,支持多个排序条件组合; 9、对于复杂的sql查询,提供获取jdbctemplate实例进行操作,类似spring jdbc的常规用法; 10、提供Entity代码生成接口,Entity并非简单的pojo(尽可能不要去修改此类),引入字段常量类,方便查询的时候指定选择字段,从而更好实现查询条件的封装; 二、为什么写SBORM? 1、hibernate:过于臃肿,使用不够灵活,优化难(其实主要是因为很少用),HQL感觉就是个渣,在 mysql几乎一统天下的背景下,跨数据库级别的兼容吃力不讨好。Hibernate的对象化关联处理确实挺强大,但是使用起来坑太多,有多少人敢在项目 中大范围使用真不知道,屠龙刀不是人人都提的起啊。 2、mybatis:轻量级,基于xml的模式感觉不利于封装,代码量不小,基于xml维护也麻烦(个人观点, 现在注解模式貌似也挺不错),感觉mybatis更适合存在dba角色的年代,可以远离代码进行sql调优,复杂的查询拼装起来也更加优雅(java基本 就是if else ...),但是对于查询业务简单但是数据库集群环境的场景有点憋屈(其实对mybatis使用也不多,瞎评论^_^)。 3、spring jdbc:小巧,灵活,足够优秀,个人比较喜欢使用,但是代码量偏大,原生的接口重复劳动量大,比如insert、mapper之类的; SBORM只是针对spring jdbc的一些不方便的地方,做了一些封装,更加简化日常的开发工作,基于spring jdbc的RowMapper自动实现对象映射,也勉强算的上叫ORM,只是大部分功能已经由spring jdbc实现了。 平时不太喜欢使用hibernate和mybatis,主要是使用spring jdbc,写这个东西的出发点主要是平时使用spring jdbc觉 得比较麻烦,重复性的代码偏多,一方面通过自动mapper降低返回结果处理工作量,另一方面参考hibernate对象化查询条件的模式,写了一个 QueryBudiler,使得更多简单的单表查询可以通过对象组织查询、更改逻辑,避免过多去写相似性的SQL语句,减少DAO接口量。 三、一些亮点 1、Entity的设计:很多人看了也许会说,这个不是POJO,不是纯粹的Java Bean,显得很另类。但是有多人在开发过程中(特别是在写sql的时候),经常要去看看表结构设计?还有多少次因为改了表某个字段,还得遍历去查找哪些 sql使用了这个字段?多少次看到在代码中直接传入字段名作为查询参数感到别扭?如果将表结构字段都用java对象去描述,能够解决这些问题,就不必要在 乎是不是POJO了,后面看example的时候应该能体会这么做的一些好处,至少我觉得是挺方便的,将大部分查询脱离表结构设计。 2、简单的数据库路由:如果分库结构不是太复杂(比如简单的读写分离、或者多个库集成),BaseDao可以自 动进行路由(比如读写分离,根据业务模式指定读、写库),如果非默认的路由规则,也可以通过手动设置的模式,进行数据库路由。数据库路由直接由 Entity指定,所有的路由都是根据Entity识别,也就是说查询也是围绕Entity展开的,避免类似使用spring jdbc的时候,各种 template实例跳来跳去,硬编码引入,写一个业务还得看看到底该用哪个template,尤其是多个数据库共用一个template实例的时候。 3、QueryBuilder:单表查询基本上都可以实现零Sql(除非查询条件特别复杂的),更新、删除等操作也可以通过QueryBuilder进行批量处理,不局限于根据主键来处理。 4、分表操作的支持:对于分表操作和常规的使用没有区别,只是指定分表规则,mybatis好像也可以通过制定参数实现分表处理,没搞清楚hibernate对这个是怎么处理的(hibernate好像是bean和表一对一绑定的)? 标签:sborm

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值