Spring 之 ORM (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没有自动的去回收空闲连接的功能!
对应的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组件,它包括三个部分:
- 基于Filter-Chain模式的插件体系。
- DruidDataSource 高效可管理的数据库连接池。
- SQLParser
对应的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)执行无返回值的存储过程:
- package com.wzj.test;
- import org.springframework.jdbc.core.JdbcTemplate;
- public class Demo{
- private JdbcTemplate jdbcTemplate;
- //省略get、set
- public void test(){
- jdbcTemplate.execute("{call procedureName(param,param...)}");
- }
- }
(2)执行返回非结果集的存储过程:
创建存储过程:- create or replace procedure get_user_name(id in varchar2,username out varchar2) is
- begin
- select username from User where userid=id;
- end
- public void test(){
- jdbcTemplate.execute(new CallableStatementCreator() {
- @Override
- public CallableStatement createCallableStatement(Connection con)
- throws SQLException {
- String userid="22";
- //创建对象
- CallableStatement cs=con.prepareCall("call get_user_name(?,?)");
- //设置参数
- cs.setString(1, userid);
- //设置输出参数
- cs.registerOutParameter(2, OracleTypes.VARCHAR);
- return cs;
- }
- }, new CallableStatementCallback() {
- @Override
- public Object doInCallableStatement(CallableStatement cs)
- throws SQLException, DataAccessException {
- //执行存储过程
- cs.execute();
- //获取输出参数
- return cs.getString(2);
- }
- });
- }
(3)执行返回结果集的存储过程:
①建立程序包:- create or replace package userpackage as
- type user_cursor is ref cursor;
- end userpackage;
- create or replace procedure get_user(user_cursor out userpackage.user_cursor) is
- begin
- open user_cursor for select * from User;
- end;
- public void test() {
- List userList = (List) jdbcTemplate.execute(
- new CallableStatementCreator() {
- public CallableStatement createCallableStatement(Connection con) throws SQLException {
- CallableStatement cs = con.prepareCall("{call get_user(?)}");
- cs.registerOutParameter(1, OracleTypes.CURSOR);// 注册输出参数的类型
- return cs;
- }
- }, new CallableStatementCallback() {
- public Object doInCallableStatement(CallableStatement cs) throws SQLException,DataAccessException {
- List userMap = new ArrayList();
- cs.execute();
- ResultSet rs = (ResultSet) cs.getObject(1);// 获取游标一行的值
- while (rs.next()) {// 转换每行的返回值到Map中
- Map rowMap = new HashMap();
- rowMap.put("userid", rs.getString("userid"));
- rowMap.put("username", rs.getString("username"));
- userMap.add(rowMap);
- }
- rs.close();
- return userMap;
- }
- });
- for (int i = 0; i < userList.size(); i++) {
- Map rowMap = (Map) userList.get(i);
- String id = rowMap.get("userid").toString();
- String name = rowMap.get("username").toString();
- System.out.println("usreid=" + id + ";username=" + name);
- }
- }