Spring4-5 Spring对JDBC的支持

  为使JDBC更加易于使用,Spring在JDBC API上定义了抽象层,以此建立一个JDBC存取框架。作为Spring JDBC框架的核心,JDBC模板的设计目的是为不同类型的JDBC操作提供模板方法,每个模板方法都能控制整个过程,并允许覆盖过程中的特定任务;该方式可以在尽可能保留灵活性的情况下, 将数据库存取的工作量降到最低。
  Spring对JDBC的支持的核心测试代码下载地址:http://download.csdn.net/download/bingbeichen/9783606。


1. 使用JdbcTemplate操作数据库

  Spring的JdbcTemplate可以实现更新、批量更新、查询单行、查询多行和查询单值等功能,具体实现步骤如下说明。
  
  第一步:额外导入C3P0数据源、MySQL数据库和JdbcTemplate所依赖的jar包,具体如下图所示:
    Spring4-5 Spring对JDBC的支持_第1张图片
  第二步:在src目录下创建db.properties文件,用于存放连接数据库所需要的基本信息,文件内容如下所示:

jdbc.user=root
jdbc.password=root
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.jdbcUrl=jdbc:mysql:///spring4

jdbc.initPoolSize=5
jdbc.maxPoolSize=10

  第三步:在src目录下创建Spring bean的配置文件applicationContext.xml,用于配置C3P0数据源和Spring的JdbcTemplate,核心配置代码如下:


<context:property-placeholder location="classpath:db.properties"/>


<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">

    <property name="user" value="${jdbc.user}">property>
    <property name="password" value="${jdbc.password}">property>
    <property name="jdbcUrl" value="${jdbc.jdbcUrl}">property>
    <property name="driverClass" value="${jdbc.driverClass}">property>

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

bean>


<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="dataSource">property>
bean>

  第四步:创建JUnit测试类,开始使用JdbcTemplate操作数据库,测试类的核心代码如下:

package com.qiaobc.spring.jdbc;

import java.util.ArrayList;
import java.util.List;

import javax.sql.DataSource;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;

public class JDBCTest {

    private ApplicationContext ctx = null;
    private JdbcTemplate jdbcTemplate = null;

    {
        ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        jdbcTemplate = (JdbcTemplate) ctx.getBean("jdbcTemplate");
    }

    /**
     * 1. 测试C3P0数据源是否配置成功
     * @throws Exception
     */
    @Test
    public void testDataSource() throws Exception {
        DataSource dataSource = ctx.getBean(DataSource.class);
        System.out.println(dataSource.getConnection());
    }

    /**
     * 2.1 更新:执行INSERT、UPDATE 或 DELETE操作
     */
    @Test
    public void testUpdate() {
        String sql = "UPDATE employees SET last_name = ? WHERE id = ?";
        jdbcTemplate.update(sql, "bb", 1);
    }

    /**
     * 2.2 批量更新:执行批量的INSERT、UPDATE 或 DELETE操作
     * 异常:Field 'id' doesn't have a default value,原因是创建表时未设置主键为自增模式
     */
    @Test
    public void testBatchUpdate() {
        String sql = "INSERT INTO employees(first_name, last_name, email) VALUES(?, ?, ?)";

        List batchArgs = new ArrayList<>();

        batchArgs.add(new Object[]{"qiao1", "jundang", "[email protected]"});
        batchArgs.add(new Object[]{"qiao2", "jundang", "[email protected]"});
        batchArgs.add(new Object[]{"qiao3", "jundang", "[email protected]"});
        batchArgs.add(new Object[]{"qiao4", "jundang", "[email protected]"});
        batchArgs.add(new Object[]{"qiao5", "jundang", "[email protected]"});

        jdbcTemplate.batchUpdate(sql, batchArgs);
    }

    /**
     * 3.1 查询单行:从数据库中获取一条记录,实际得到对应的对象
     * 注意:不是调用queryForObject(String sql, Class requiredType, Object... args)方法
     * 而需要调用queryForObject(String sql, RowMapper rowMapper, Object... args)方法:
     *      1). RowMapper用于指定如何映射结果集的行,常用的实现类为BeanPropertyRowMapper
     *      2). 使用SQL语句中列的别名完成列名和类属性名的映射,如first_name firstName
     *      3). 不支持级联属性的映射,JdbcTemplate的实质仍是JDBC而不是ORM
     */
    @Test
    public void testQueryForObject() {
        String sql = "SELECT id, last_name lastName, first_name firstName, email FROM employees WHERE id = ?";

        RowMapper rowMapper = new BeanPropertyRowMapper<>(Employee.class);
        Employee employee = jdbcTemplate.queryForObject(sql, rowMapper, 5);

        System.out.println(employee);
    }

    /**
     * 3.2 查询多行:获取实体类的集合
     */
    @Test
    public void testQueryForList() {
        String sql = "SELECT id, last_name lastName, first_name firstName, email FROM employees WHERE id > ?";

        RowMapper rowMapper = new BeanPropertyRowMapper<>(Employee.class);
        List employees = jdbcTemplate.query(sql, rowMapper , 2);

        System.out.println(employees);
    }

    /**
     * 3.3 获取单个列的值或做统计查询
     * 使用queryForObject(String sql, Class requiredType)
     */
    @Test
    public void testQueryForValue() {
        String sql = "SELECT count(id) FROM employees";
        Integer count = jdbcTemplate.queryForObject(sql, Integer.class);
        System.out.println(count);
    }

}

2. 使用JdbcTemplate实现DAO类

  JdbcTemplate利用了Java 1.5的特性(自动装箱、泛型、可变长度等)来简化开发,其实现DAO类的方式主要有两种,具体说明如下:

  • 推荐使用: JdbcTemplate类是线程安全的,可在IoC容器中声明其单个实例后,将该实例注入到所有的DAO类中;
  • 较少使用: Spring的JDBC框架还提供JdbcDaoSupport类来简化DAO实现,其声明了jdbcTemplate属性,可以从IOC容器中注入或自动从数据源中创建。

2.1 方式一:注入JdbcTemplate

package com.qiaobc.spring.jdbc.dao;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;

import com.qiaobc.spring.jdbc.Employee;

/**
 * 推荐使用:在使用时仅创建一个JdbcTemplate的实例即可使用
 * 需要在配置文件中设置自动扫描该类:
 *  
 * @author qiaobc
 *
 */
@Repository
public class EmployeeDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    public Employee get(Integer id) {
        String sql = "SELECT id, first_name firstName, last_name lastName, email FROM employees WHERE id = ?";
        RowMapper rowMapper = new BeanPropertyRowMapper<>(Employee.class);
        return jdbcTemplate.queryForObject(sql, rowMapper , id);
    }

}

2.2 方式二:扩展JdbcDaoSupport

package com.qiaobc.spring.jdbc.dao;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.springframework.stereotype.Repository;

import com.qiaobc.spring.jdbc.Employee;

/**
 * 不推荐使用,推荐直接使用JdbcTemplate作为DAO类的成员变量
 * @author qiaobc
 * Caused by: java.lang.IllegalArgumentException: 'dataSource' or 'jdbcTemplate' is required
 */
@Repository
public class EmployeeKzDao extends JdbcDaoSupport {

    @Autowired
    public void setDataSource1(DataSource dataSource) { // 其父类的setDataSource()方法是final的
        setDataSource(dataSource);
    }

    public Employee get(Integer id) {
        String sql = "SELECT id, first_name firstName, last_name lastName, email FROM employees WHERE id = ?";
        RowMapper rowMapper = new BeanPropertyRowMapper<>(Employee.class);
        return getJdbcTemplate().queryForObject(sql, rowMapper , id);
    }

}

3. 在JDBC模板中使用具名参数

  Spring的NamedParameterJdbcTemplate类支持具名参数,即SQL语句按名称(以冒号开头)而不是按位置(以?号表示)进行参数绑定,其更易于维护且可读性较强。

@Test
public void testNamedParameterJdbcTemplate() {
    String sql = "INSERT INTO employees(first_name, last_name, email) VALUES(:firstName, :lastName, :email)";

    // 可以使用具名参数,即按名称进行参数绑定,但较为麻烦
    Map<String, Object> paramMap = new HashMap<String, Object>();
    paramMap.put("firstName", "qiao");
    paramMap.put("lastName", "bei");
    paramMap.put("email", "[email protected]");
    namedParameterJdbcTemplate.update(sql, paramMap);

    // 使用update(String sql, SqlParameterSource paramSource)方法实现更新操作较为简单,要求具名参数名和类的属性名相同
    Employee employee = new Employee(null, "qiao", "dabei", "[email protected]");
    SqlParameterSource paramSource = new BeanPropertySqlParameterSource(employee);
    namedParameterJdbcTemplate.update(sql, paramSource);
}

你可能感兴趣的:(Spring4-5 Spring对JDBC的支持)