一 JdbcTemplate简介

  Spring对数据库的操作在jdbc上面做了深层次的封装,使用spring的注入功能,可以把DataSource注册到JdbcTemplate之中。

  JdbcTemplate位于

springboot jpa 自定义sql批量更新 spring jpa update_spring

中。其全限定命名为org.springframework.jdbc.core.JdbcTemplate。要使用JdbcTemlate还需一个

springboot jpa 自定义sql批量更新 spring jpa update_spring_02

这个包包含了一下事务和异常控制。

二 JdbcTemplate主要提供以下五类方法:

  • 1 execute方法:可以用于执行任何SQL语句,一般用于执行DDL语句;
  • 2 update方法及batchUpdate方法:update方法用于执行新增、修改、删除等语句;
  • 3 batchUpdate方法用于执行批处理相关语句;
  • 4 query方法及queryForXXX方法:用于执行查询相关语句;
  • 5 call方法:用于执行存储过程、函数相关语句。

三 下面进行案件分析

在src下面新建一个属性配置文件

springboot jpa 自定义sql批量更新 spring jpa update_bc_03

1 jdbc.user=root
2 jdbc.password=123456
3 jdbc.driverClass=com.mysql.jdbc.Driver
4 jdbc.jdbcUrl=jdbc\:mysql\:///test

我们通常将数据库的配置信息单独放到一个文件中,这样也为了方便后期维护

配置Spring配置文件applicationContext.xml

<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="driverClass" value="${jdbc.driverClass}"></property>
    <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
</bean>

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

第一行代码:用来读取db.properties文件中的数据。

  第二行代码:用来配置一个数据源,这里数据实现类来自C3P0中的一个属性类。其中属性的值就是来自于db.properties

  第九行代码:配置一个JdbcTemplate实例,并注入一个dataSource数据源

四 测试代码

1、update()方法

(1)jdbcTemplate执行更新操作:

a、通过update插入单个数据

@Test
	public void testUpdate() {
		String sql = "UPDATE employees SET last_name = ? WHERE id = ?";
		jdbcTemplate.update(sql, "XXX", 5);
	}

b、通过update修改数据

1 String sql="update user set name=?,deptid=? where id=?";
2 jdbcTemplate.update(sql,new Object[]{"zhh",5,51});

c、通过update删除数据

1 String sql="delete from user where id=?";
2 jdbcTemplate.update(sql,51);

 (2)具名参数NamedParameterJdbcTemplate执行更新操作:

两种方法:

/**
	 * 可以为参数起名字
	 * 1. 好处:若有多个参数,则不用再去对应位置,直接对参数名,便于维护
	 * 2. 坏处:较为麻烦.
	 * 	
	 */
	@Test
	public void testNamedParameterJdbcTemplate() {
		String sql = "INSERT INTO employees(last_name, email, dept_id) VALUES(:ln, :email, :deptid)";
		Map<String, Object> paramMap = new HashMap<>();
		paramMap.put("ln", "FF");
		paramMap.put("email", "ff@qq.com");
		paramMap.put("deptid", "5");
		namedParameterJdbcTemplate.update(sql, paramMap);
	}
	
	/**
	 * 使用具名参数时,可以使用update(String sql, SqlParameterSource paramSource)方法进行更新操作
	 * 1. SQL语句中的参数名与类的属性一直
	 * 2. 使用SqlParameterSource的BeanPropertySqlParameterSource实现类作为参数.
	 */
	@Test
	public void testNamedParameterJdbcTemplate2() {
		String sql = "INSERT INTO employees(last_name, email, dept_id) "
				+ "VALUES(:lastname, :email, :deptId)";
		Employee employee = new Employee();
		employee.setLastname("xyz");
		employee.setEmail("xyz@sina.com");
		employee.setDeptId(3);
		
		SqlParameterSource paramSource = new BeanPropertySqlParameterSource(employee);
		namedParameterJdbcTemplate.update(sql, paramSource);
	}

2、batchUpdate()批量插入、更新和删除方法

a、批量插入

/**
	 * 批量更新:执行多条sql语句,INSERT, UPDATE, DELETE
	 * 最后一个参数是Object[] 的List类型:因为修改一条记录需要一个Object的数组, 
	 * 多条sql语句就需要多个Object的数组
	 */
	@Test
	public void testBatchUpdate() {
		//插入多条记录
		String sql = "INSERT INTO employees(last_name, email, dept_id) VALUES(?, ?, ?)";
		List<Object []> batchArgs = new ArrayList<>();
		batchArgs.add(new Object[]{"AA", "aa@qq.com", 1});
		batchArgs.add(new Object[]{"BB", "bb@qq.com", 2});
		batchArgs.add(new Object[]{"CC", "cc@qq.com", 3});
		batchArgs.add(new Object[]{"DD", "dd@qq.com", 3});
		batchArgs.add(new Object[]{"EE", "ee@qq.com", 2});
		//batchArgs这是一个数组链表
		jdbcTemplate.batchUpdate(sql, batchArgs);
	}

batchUpdate方法第二参数是一个元素为Object[]数组类型的List集合.

3、从数据中读取数据到实体对象

Employee类:

package com.primary.spring.jdbc;

public class Employee {

	private Integer id;
	private String lastname;
	private String email;
	private Integer deptId;

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getLastname() {
		return lastname;
	}

	public void setLastname(String lastname) {
		this.lastname = lastname;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public Integer getDeptId() {
		return deptId;
	}

	public void setDeptId(Integer deptId) {
		this.deptId = deptId;
	}

	@Override
	public String toString() {
		return "Employee [id=" + id + ", lastname=" + lastname + ", email=" + email + ", deptId=" + deptId + "]";
	}
}

a、读取单个对象

/**
	 * 从数据库中获取一条记录,实际得到一个对象
	 * 调用queryForObject(String sql, RowMapper<Employee> rowMapper, Object... args)
	 * 1. 其中的rowMapper 指定如何去映射结果集的行,常用的实现类为BeanPropertyRowMapper
	 * 2. 使用sql中列的别名完成列名和类的属性名映射,例如last_name lastname
	 * 3. 不支持级联属性dept_id as department.id
	 */
	@Test
	public void testQueryForObject() {
		//last_name表中的列名,lastname类的属性名
		String sql = "SELECT id, last_name lastname, email, dept_id as department.id FROM employees WHERE id = ?";
		RowMapper<Employee> rowMapper = new BeanPropertyRowMapper<>(Employee.class);
		Employee employee = jdbcTemplate.queryForObject(sql, rowMapper, 1);
		System.out.println(employee);
	}

1、使用BeanProperytRowMapper要求sql数据查询出来的列和实体属性需要一一对应。如果数据中列明和属性名不一致,在sql语句中需要用as重新取一个别名

2、使用JdbcTemplate对象不能获取关联对象

b、读取多个对象

/**
	 * 查找实体类的集合
	 * 注意:调用的不是QueryForList的方法
	 */
	@Test
	public void testQueryForList() {
		String sql = "SELECT id, last_name lastname, email FROM employees WHERE id > ?";
		RowMapper<Employee> rowMapper = new BeanPropertyRowMapper<>(Employee.class);
		List<Employee> employees = jdbcTemplate.query(sql, rowMapper, 8);
		System.out.println(employees);
	}

c、获取某个记录某列或者count、avg、sum等函数返回唯一值 

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

 五 在实际开发中可以怎样用

1 使用JdbcTemplate:

EmployeeDao:(按id查询结果)

package com.primary.spring.jdbc;

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;
@Repository
public class EmployeeDao {

	@Autowired //配置自动扫描的bean
	private JdbcTemplate jdbcTemplate;
	
	public Employee get(Integer id) {
		String sql = "SELECT id, last_name lastname, email FROM employees WHERE id = ?";
		RowMapper<Employee> rowMapper = new BeanPropertyRowMapper<>(Employee.class);
		Employee employee = jdbcTemplate.queryForObject(sql, rowMapper, id);
		
		return employee;
	}
	
}

xml配置:

<!-- 配置Spring的JDBC模板类Template -->
	<bean id="jdbcTemplate"
		class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	
<!-- 为EmployeeDao配置自动扫描的bean -->
	<context:component-scan base-package="com.primary.spring.jdbc"></context:component-scan>

2 继承JdbcDaoSupport(但不推荐此方法)

DepartmentDao类:

package com.primary.spring.jdbc;



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;
/**
 * 不推荐使用JdbcDaoSupport,而推荐使用JdbcTemplate作为Dao 类的成员变量
 * @author lenovo
 *
 */
@Repository
public class DepartmentDao extends JdbcDaoSupport{

	@Autowired
	public void setDataSource2(DataSource dataSource) {
		setDataSource(dataSource);
	}
	
	public Department get(Integer id) {
		String sql = "SELECT id, dept_name name FROM departments WHERE id = ?";
		RowMapper<Department> rowMapper = new BeanPropertyRowMapper<>(Department.class);
		return getJdbcTemplate().queryForObject(sql, rowMapper, id);
	}
}

完整源码:

applicationContext.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
	
	<!-- 导入资源文件 -->
	<context:property-placeholder location="classpath:db.properties" />
	<!-- 配置c3p0数据源 -->
	<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>
	
	<!-- 配置Spring的JDBC模板类Template -->
	<bean id="jdbcTemplate"
		class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	
	<!-- 为EmployeeDao配置自动扫描的bean -->
	<context:component-scan base-package="com.primary.spring.jdbc"></context:component-scan>
	
	<!-- 配置NamedParameterJdbcTemplate, 该对象可以使用具名参数,其没有无参构造器,所以必须为其构造器指定参数 -->
	<bean id="namedParameterJdbcTemplate"
		class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
		<constructor-arg ref="dataSource"></constructor-arg>
	</bean>
	
	
</beans>

JDBCTest.java: 

package com.primary.spring.jdbc;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.sql.DataSource;

import org.junit.jupiter.api.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;
import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;

class JDBCTest {
	
	private ApplicationContext ctx = null;
	private JdbcTemplate jdbcTemplate;
	private EmployeeDao employeeDao;
	private DepartmentDao departmentDao;
	private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
	{
		ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
		jdbcTemplate = (JdbcTemplate) ctx.getBean("jdbcTemplate");
		employeeDao = ctx.getBean(EmployeeDao.class);
		departmentDao = ctx.getBean(DepartmentDao.class);
		namedParameterJdbcTemplate = ctx.getBean(NamedParameterJdbcTemplate.class);
	}

	/**
	 * EmployeeDao的测试类
	 */
	@Test
	public void testEmployeeDao() {
		System.out.println(employeeDao.get(2));
	}
	
	/**
	 * DepartmentDao测试类
	 */
	@Test
	public void testDepartmentDao() {
		System.out.println(departmentDao.get(1));
	}
	
	
	/**
	 * 连接数据库
	 * @throws SQLException
	 */
	@Test
	public void testDataSource() throws SQLException{
		DataSource dataSource = (DataSource) ctx.getBean("dataSource");
		System.out.println(dataSource.getConnection());
	}
	
	
	/**
	 * 执行INSERT, UPDATE, DELETE
	 */
	@Test
	public void testUpdate() {
		String sql = "UPDATE employees SET last_name = ? WHERE id = ?";
		jdbcTemplate.update(sql, "wangjian", 5);
	}
	
	/**
	 * 批量更新:执行多条sql语句,INSERT, UPDATE, DELETE
	 * 最后一个参数是Object[] 的List类型:因为修改一条记录需要一个Object的数组, 
	 * 多条sql语句就需要多个Object的数组
	 */
	@Test
	public void testBatchUpdate() {
		//插入多条记录
		String sql = "INSERT INTO employees(last_name, email, dept_id) VALUES(?, ?, ?)";
		List<Object []> batchArgs = new ArrayList<>();
		batchArgs.add(new Object[]{"AA", "aa@qq.com", 1});
		batchArgs.add(new Object[]{"BB", "bb@qq.com", 2});
		batchArgs.add(new Object[]{"CC", "cc@qq.com", 3});
		batchArgs.add(new Object[]{"DD", "dd@qq.com", 3});
		batchArgs.add(new Object[]{"EE", "ee@qq.com", 2});
		//batchArgs这是一个数组链表
		jdbcTemplate.batchUpdate(sql, batchArgs);
	}
	
	/**
	 * 从数据库中获取一条记录,实际得到一个对象
	 * 调用queryForObject(String sql, RowMapper<Employee> rowMapper, Object... args)
	 * 1. 其中的rowMapper 指定如何去映射结果集的行,常用的实现类为BeanPropertyRowMapper
	 * 2. 使用sql中列的别名完成列名和类的属性名映射,例如last_name lastname
	 * 3. 不支持级联属性dept_id as department.id
	 */
	@Test
	public void testQueryForObject() {
		//last_name表中的列名,lastname类的属性名
		String sql = "SELECT id, last_name lastname, email, dept_id as department.id FROM employees WHERE id = ?";
		RowMapper<Employee> rowMapper = new BeanPropertyRowMapper<>(Employee.class);
		Employee employee = jdbcTemplate.queryForObject(sql, rowMapper, 1);
		System.out.println(employee);
	}
	
	/**
	 * 查找实体类的集合
	 * 注意:调用的不是QueryForList的方法
	 */
	@Test
	public void testQueryForList() {
		String sql = "SELECT id, last_name lastname, email FROM employees WHERE id > ?";
		RowMapper<Employee> rowMapper = new BeanPropertyRowMapper<>(Employee.class);
		List<Employee> employees = jdbcTemplate.query(sql, rowMapper, 8);
		System.out.println(employees);
	}
	

	/**
	 * 获取单个列的值或做统计查询
	 * 使用queryForObject(String sql, Class<Long> requiredType)
	 */
	@Test
	public void testOueryForObject2() {
		String sql = "SELECT count(id) FROM employees";
		long count = jdbcTemplate.queryForObject(sql, Long.class);
		System.out.println(count);
	}
	
	/**
	 * 可以为参数起名字
	 * 1. 好处:若有多个参数,则不用再去对应位置,直接对参数名,便于维护
	 * 2. 坏处:较为麻烦.
	 * 	
	 */
	@Test
	public void testNamedParameterJdbcTemplate() {
		String sql = "INSERT INTO employees(last_name, email, dept_id) VALUES(:ln, :email, :deptid)";
		Map<String, Object> paramMap = new HashMap<>();
		paramMap.put("ln", "FF");
		paramMap.put("email", "ff@qq.com");
		paramMap.put("deptid", "5");
		namedParameterJdbcTemplate.update(sql, paramMap);
	}
	
	/**
	 * 使用具名参数时,可以使用update(String sql, SqlParameterSource paramSource)方法进行更新操作
	 * 1. SQL语句中的参数名与类的属性一直
	 * 2. 使用SqlParameterSource的BeanPropertySqlParameterSource实现类作为参数.
	 */
	@Test
	public void testNamedParameterJdbcTemplate2() {
		String sql = "INSERT INTO employees(last_name, email, dept_id) "
				+ "VALUES(:lastname, :email, :deptId)";
		Employee employee = new Employee();
		employee.setLastname("xyz");
		employee.setEmail("xyz@sina.com");
		employee.setDeptId(3);
		
		SqlParameterSource paramSource = new BeanPropertySqlParameterSource(employee);
		namedParameterJdbcTemplate.update(sql, paramSource);
	}
}