[原创]java WEB学习笔记109:Spring学习---spring对JDBC的支持:使用 JdbcTemplate 查询数据库,简化 JDBC 模板查询,在 JDBC 模板中使用具名参数两种实现
本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用
内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系。
本人互联网技术爱好者,互联网技术发烧友
微博:伊直都在0221
QQ:951226918
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1.JdbcTemplate 简介
1)为了使 JDBC 更加易于使用, Spring 在 JDBC API 上定义了一个抽象层, 以此建立一个 JDBC 存取框架.
2)作为 Spring JDBC 框架的核心, JDBC 模板的设计目的是为不同类型的 JDBC 操作提供模板方法. 每个模板方法都能控制整个过程, 并允许覆盖过程中的特定任务. 通过这种方式, 可以在尽可能保留灵活性的情况下, 将数据库存取的工作量降到最低.
本篇主要讲述JdbcTemplate 相关的API,主要以代码为例
2.构建工程 及 部分代码
1)导入spring jar,额外加入 mysql c3p0 jar包
2)在配置文件中配置c3p0数据源
db.properties
1 jdbc.user=root
2 jdbc.password=zhangzhen
3 jdbc.driverClass=com.mysql.jdbc.Driver
4 jdbc.jdbcUrl=jdbc:mysql:///spring
5
6 jdbc.initPoolSize=5
7 jdbc.maxPoolSize=10
在配置文件中配置c3p0文件
1 <!-- 导入资源文件 -->
2 <context:property-placeholder location="classpath:db.properties"/>
3 <!-- 配置c3p0 数据源 -->
4 <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
5 <property name="user" value="${jdbc.user}"></property>
6 <property name="password" value="${jdbc.password}"></property>
7 <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
8 <property name="driverClass" value="${jdbc.driverClass}"></property>
9
10 <property name="initialPoolSize" value="${jdbc.initPoolSize}"></property>
11 <property name="maxPoolSize" value="${jdbc.maxPoolSize}"></property>
12 </bean>
3)配置 Spring 的jdbcTemplate
1 <!-- 配置Spring 的jdbcTemplate -->
2 <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
3 <property name="dataSource" ref="dataSource"></property>
4 </bean>
3.完整代码
application.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 的jdbcTemplate -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
</beans>
Department.java
1 package com.jason.spring.jdbc;
2
3 public class Department {
4
5 private Integer id;
6 private String name;
7
8 public Integer getId() {
9 return id;
10 }
11
12 public void setId(Integer id) {
13 this.id = id;
14 }
15
16 public String getName() {
17 return name;
18 }
19
20 public void setName(String name) {
21 this.name = name;
22 }
23
24 @Override
25 public String toString() {
26 return "Department [id=" + id + ", name=" + name + "]";
27 }
28
29 }
Employee.java
1 package com.jason.spring.jdbc;
2
3 public class Employee {
4
5 private Integer id;
6 private String lastName;
7 private String email;
8
9 private Department department;
10
11 public Integer getId() {
12 return id;
13 }
14
15 public void setId(Integer id) {
16 this.id = id;
17 }
18
19 public String getLastName() {
20 return lastName;
21 }
22
23 public void setLastName(String lastName) {
24 this.lastName = lastName;
25 }
26
27 public String getEmail() {
28 return email;
29 }
30
31 public void setEmail(String email) {
32 this.email = email;
33 }
34
35 public Department getDepartment() {
36 return department;
37 }
38
39 public void setDepartment(Department department) {
40 this.department = department;
41 }
42
43 @Override
44 public String toString() {
45 return "Employee [id=" + id + ", lastName=" + lastName + ", email="
46 + email + ", department=" + department + "]";
47 }
48
49 }
单元测试类
1 package com.jason.spring.jdbc;
2
3 import static org.junit.Assert.*;
4
5 import java.sql.SQLException;
6 import java.util.ArrayList;
7 import java.util.List;
8
9 import javax.sql.DataSource;
10
11 import org.junit.Test;
12 import org.springframework.context.ApplicationContext;
13 import org.springframework.context.support.ClassPathXmlApplicationContext;
14 import org.springframework.jdbc.core.BeanPropertyRowMapper;
15 import org.springframework.jdbc.core.JdbcTemplate;
16 import org.springframework.jdbc.core.RowMapper;
17
18
19 public class JDBCTest {
20
21 private ApplicationContext ctx = null;
22 private JdbcTemplate jdbcTemplate;
23
24 {
25 ctx = new ClassPathXmlApplicationContext("application.xml");
26 jdbcTemplate = (JdbcTemplate) ctx.getBean("jdbcTemplate");
27
28 }
29
30 /**
31 *
32 * @Author:jason_zhangz@163.com
33 * @Title: testQueryForObject2
34 * @Time:2016年12月6日
35 * @Description: 获取单个列的值,或做统计查询
36 * 使用 queryForObject(String sql, Class<Long> requiredType) 方法
37 *
38 */
39 @Test
40 public void testQueryForObject2(){
41 String sql ="SELECT count(id) FROM employee ";
42 long count = jdbcTemplate.queryForObject(sql, Long.class);
43 System.out.println(count);
44 }
45
46 /**
47 *
48 * @Author:jason_zhangz@163.com
49 * @Title: testQueryForList
50 * @Time:2016年12月6日
51 * @Description: 查到实体类的集合
52 * 注意:调用的方法不是queryForList
53 *
54 */
55 @Test
56 public void testQueryForList(){
57 String sql = "SELECT id, last_name lastName, email FROM employee WHERE id > ?";
58 RowMapper<Employee> rowMapper = new BeanPropertyRowMapper<>(Employee.class);
59 List<Employee> employees = jdbcTemplate.query(sql, rowMapper, 5);
60 System.out.println(employees);
61 }
62
63 /**
64 *
65 * @Author:jason_zhangz@163.com
66 * @Title: testQueryForObject
67 * @Time:2016年12月6日
68 * @Description: 从数据库中获取一条记录,实际得到对应的对象
69 * 注意:.queryForObject(String sql, Class<Employee> requiredType, Object... args) 返回的是一个字段
70 * 需要使用:queryForObject(String sql, RowMapper<Employee> rowMapper, Object... args)
71 * 1.RowMapper 指定如何映射结果的行,常用的实现类为 BeanPropertyRowMapper
72 * 2.使用SQL 中列的别名完成列名 和 类的属性名的映射:last_name lastName
73 * 3.不支持级联属性,jdbcTemplate 是一个JDBC的小工具,不是ORM框架
74 *
75 */
76 @Test
77 public void testQueryForObject(){
78 String sql = "SELECT id, last_name lastName, email, dept_id as \"department.id\" FROM employee WHERE id = ?";
79 RowMapper<Employee> rowMapper = new BeanPropertyRowMapper<>(Employee.class);
80 Employee employee = jdbcTemplate.queryForObject(sql, rowMapper, 1);
81 System.out.println(employee);
82 }
83
84
85
86 /**
87 *
88 * @Author:jason_zhangz@163.com
89 * @Title: testBatchUpdate
90 * @Time:2016年12月6日
91 * @Description: 执行批量的 INSERT, UPDATE, DELETE
92 * 最后一个参数是Object[] 的list 类型:因为修改一条记录需要一个Object 数据,多条记录 对应多个Object 形成数组
93 */
94 @Test
95 public void testBatchUpdate(){
96 String sql = "INSERT INTO employee(last_name, email, dept_id) VALUES(?,?,?)";
97 List<Object[]> batchArgs = new ArrayList<>();
98 batchArgs.add(new Object[]{"AA","AA@163.com",1});
99 batchArgs.add(new Object[]{"bb","bb@163.com",2});
100 batchArgs.add(new Object[]{"cc","cc@163.com",3});
101 batchArgs.add(new Object[]{"dd","dd@163.com",4});
102 batchArgs.add(new Object[]{"ee","ee@163.com",5});
103 batchArgs.add(new Object[]{"ff","ff@163.com",1});
104 jdbcTemplate.batchUpdate(sql, batchArgs);
105
106 }
107
108
109 /**
110 *
111 * @Author:jason_zhangz@163.com
112 * @Title: testUpdate
113 * @Time:2016年12月6日
114 * @Description: 执行 INSERT, UPDATE, DELETE
115 *
116 */
117 @Test
118 public void testUpdate(){
119 String sql = "UPDATE employee SET last_name = ? WHERE id = ?";
120 jdbcTemplate.update(sql,"JACK",4);
121
122 }
123
124
125
126 @Test
127 public void testDataSource() throws SQLException {
128 DataSource dataSources = ctx.getBean(DataSource.class);
129 System.out.println(dataSources.getConnection());
130 }
131
132 }
4.简化 JDBC 模板查询
1)每次使用都创建一个 JdbcTemplate 的新实例, 这种做法效率很低下.
2)JdbcTemplate 类被设计成为线程安全的, 所以可以再 IOC 容器中声明它的单个实例, 并将这个实例注入到所有的 DAO 实例中.
3)JdbcTemplate 也利用了 Java 1.5 的特定(自动装箱, 泛型, 可变长度等)来简化开发
注入JDBC 模板
注解方式实现自动注入
1 import org.springframework.beans.factory.annotation.Autowired;
2 import org.springframework.jdbc.core.BeanPropertyRowMapper;
3 import org.springframework.jdbc.core.JdbcTemplate;
4 import org.springframework.jdbc.core.RowMapper;
5 import org.springframework.stereotype.Repository;
6
7 @Repository
8 public class EmployeeDao {
9
10 @Autowired
11 private JdbcTemplate jdbcTemplate;
12
13 public Employee get(Integer id){
14 String sql = "SELECT id, last_name lastName, email FROM employees WHERE id = ?";
15 RowMapper<Employee> rowMapper = new BeanPropertyRowMapper<>(Employee.class);
16 Employee employee = jdbcTemplate.queryForObject(sql, rowMapper, id);
17
18 return employee;
19 }
20 }
5.在 JDBC 模板中使用具名参数
1)在经典的 JDBC 用法中, SQL 参数是用占位符 ? 表示,并且受到位置的限制. 定位参数的问题在于, 一旦参数的顺序发生变化, 就必须改变参数绑定.
2)在 Spring JDBC 框架中, 绑定 SQL 参数的另一种选择是使用具名参数(named parameter).
3)具名参数: SQL 按名称(以冒号开头)而不是按位置进行指定. 具名参数更易于维护, 也提升了可读性. 具名参数由框架类在运行时用占位符取代
4)具名参数只在 NamedParameterJdbcTemplate 中得到支持
具体实现
5)在 SQL 语句中使用具名参数时, 可以在一个 Map 中提供参数值, 参数名为键
6)也可以使用 SqlParameterSource 参数
7)批量更新时可以提供 Map 或 SqlParameterSource 的数组
1 public class JDBCTest {
2
3 private ApplicationContext ctx = null;
4 private JdbcTemplate jdbcTemplate;
5 private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
6
7 {
8 ctx = new ClassPathXmlApplicationContext("application.xml");
9 jdbcTemplate = (JdbcTemplate) ctx.getBean("jdbcTemplate");
10 namedParameterJdbcTemplate = (NamedParameterJdbcTemplate) ctx.getBean("namedParameterJdbcTemplate");
11
12 }
13
14 /*
15 * 使用具名参数使用这个方法:update(String sql, SqlParameterSource paramSource)
16 * 1.sql 语句中的参数名 和 类的属性一致
17 * 2.使用 SqlParameterSource 的 BeanPropertySqlParameterSource实现类,作为参数
18 */
19 @Test
20 public void testNamedParameterJdbcTemplate2(){
21 String sql = "INSERT INTO employee(last_name, email, dept_id) VALUES(:lastName, :email, :deptId)";
22 Employee employee = new Employee();
23 employee.setLastName("wl");
24 employee.setEmail("wl@sina.com");
25 employee.setDeptId(5);
26
27 SqlParameterSource parameterSource = new BeanPropertySqlParameterSource(employee);
28 namedParameterJdbcTemplate.update(sql, parameterSource);
29
30 }
31
32 /**
33 *
34 * @Author:jason_zhangz@163.com
35 * @Title: testNamedParameterJdbcTemplate
36 * @Time:2016年12月6日
37 * @Description: 使用具名参数
38 * 可以为参数起名
39 * 1.好处:若有多个参数,则不用再去对应位置,直接对应参数名,便于维护
40 * 2.缺点:较为麻烦一台
41 *
42 */
43 @Test
44 public void testNamedParameterJdbcTemplate(){
45 String sql = "INSERT INTO employee(last_name, email, dept_id) VALUES(:ln, :email, :deptid)";
46 Map<String, Object> paramMap = new HashMap<String, Object>();
47 paramMap.put("ln", "FF");
48 paramMap.put("email", "ff@163.com");
49 paramMap.put("deptid", 5);
50 namedParameterJdbcTemplate.update(sql, paramMap);
51 }
52 }
配置namedParameterJdbcTemplate 的bean
1 <!-- 配置具名参数 namedParameterJdbcTemplate,该对象可以使用具名参数,其没有无参数的构造器,必须为其构造器指定参数,一般为dataSource -->
2 <bean id="namedParameterJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
3 <constructor-arg ref="dataSource"></constructor-arg>
4 </bean>
5