第五章 征服数据库
5.1 数据库的访问哲学
DAO是数据访问对象(data access object)的缩写。
5.1.1 了解Spring的数据访问异常体系
可能抛出的SQLException常见问题:
- 应用程序无法连接数据库;
- 要执行的查询有语法错误
- 查询中所使用的表和列不存在
- 视图插入或更新数据违反了数据库完整性约束
Spring的凭条无关持久化异常
spring的异常都继承自DataAccessException(他是一个非检查型异常)。
5.1.2 数据访问模板化
spring将数据访问过程中固定的和可变的部分明确划分为两个不同的类:模板类(template)和回调(callback)。模板管理过程汇总固定的部分,回调处理自定义的数据访问代码。
5.1.3 使用DAO支持类
应用程序的DAO继承自JdbcDaoSupport,调用getJdbcTemplate()方法获得JcbcTemplate;可以直接处理JDBC连接;
5.2 配置数据源
spring提供了在Spring上下文配置数据源Bean的多种方式,包括:
- 通过JDBC驱动成语定义的数据源
- 通过JNDI查找数据源
- 连接池的数据源
5.2.1 使用JNDI数据源
先略过....
5.2.2 使用数据源连接池
首先配置pom.xml,用dbcp的jar提供连接池功能:
1 <!-- 配置数据源的链接dbcp( 提供链接池功能)--> 2 <dependency> 3 <groupId>commons-dbcp</groupId> 4 <artifactId>commons-dbcp</artifactId> 5 <version>1.3</version> 6 </dependency>
下载的jar包如下:
在springbean.xml中配置:
1 <!--基于dbcp 配置数据源 --> 2 <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> 3 <property name="driverClassName" value="com.mysql.jdbc.Driver"></property> 4 <property name="url" value="jdbc:mysql://localhost:3306/test"></property> 5 <property name="username" value="root"></property> 6 <property name="password" value="mysql"></property> 7 <property name="initialSize" value="5"></property> 8 <property name="maxActive" value="10"></property> 9 </bean>
测试代码:
1 package com.springinaction.test; 2 3 import org.apache.commons.dbcp.BasicDataSource; 4 import org.junit.Test; 5 6 7 import org.springframework.context.ApplicationContext; 8 import org.springframework.context.support.ClassPathXmlApplicationContext; 9 10 import com.springinaction.springidol.Auditorium; 11 import com.springinaction.springidol.Instrumentalist; 12 import com.springinaction.springidol.Magician; 13 import com.springinaction.springidol.MindReader; 14 import com.springinaction.springidol.OneManBand; 15 import com.springinaction.springidol.Performer; 16 import com.springinaction.springidol.PoeticJuggler; 17 import com.springinaction.springidol.Stage; 18 import com.springinaction.springidol.Thinker; 19 import com.springinaction.springidol.Ticket; 20 import com.springinaction.springidol.Volunteer; 21 22 23 public class TestCase { 24 25 //这个ClassPathXmlApplicationContext是springframe-context中 26 //org.springframework.context.support包下的类 27 ApplicationContext ac = new ClassPathXmlApplicationContext("spring/springbean.xml");//注意路径 28 29 //测试数据源配置 30 @Test 31 public void testData() throws Exception { 32 33 BasicDataSource dataSource = (BasicDataSource)ac.getBean("dataSource"); 34 35 System.out.println(dataSource.getInitialSize()); 36 37 System.out.println(dataSource.getDriverClassName()); 38 39 } 40 41 42 43 }
结果如下:
5.2.3 基于JDBC驱动的数据源
spring提供了两种数据源供选择(org.springframework,jdbc,datasource):
- DriverManagerDataSource:在每个连接请求时都会范湖一个新建的链接。与DBCP的BasicDataSource不同,由DriverManagerDataSource提供的链接并没有进行池化管理。
- SingleConnectionDataSource:在每个链接请求时都会返回同一个链接,
配置spring-jdbc,首先pom.xml中:
1 <!-- spring-jdbc配置数据源 --> 2 <dependency> 3 <groupId>org.springframework</groupId> 4 <artifactId>spring-jdbc</artifactId> 5 <version>4.2.9.RELEASE</version> 6 </dependency>
会引进两个包,一个jdbc包,一个事物处理包:
1 <!--基于dbcp 配置数据源 --> 2 <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> 3 <property name="driverClassName" value="com.mysql.jdbc.Driver"></property> 4 <property name="url" value="jdbc:mysql://localhost:3306/test"></property> 5 <property name="username" value="root"></property> 6 <property name="password" value="mysql"></property> 7 <!-- <property name="initialSize" value="5"></property> 8 <property name="maxActive" value="10"></property> --> 9 </bean>
在pom.xml配置中引入mysql数据库的驱动包:
1 <!-- mysql的链接的驱动包 --> 2 <dependency> 3 <groupId>mysql</groupId> 4 <artifactId>mysql-connector-java</artifactId> 5 <version>5.1.40</version> 6 </dependency>
1 //测试spring数据源配置 2 @Test 3 public void testSpringData() throws Exception { 4 5 DriverManagerDataSource dataSource = (DriverManagerDataSource)ac.getBean("dataSource"); 6 7 Connection connection = dataSource.getConnection(); 8 9 Statement createStatement = connection.createStatement(); 10 11 ResultSet rs = createStatement.executeQuery("select * from user"); 12 13 while(rs.next()){ 14 System.out.println(rs.getString("username")); 15 } 16 17 }
结果:
5.3 在Spring中使用JDBC
5.3.1 失控的JDBC代码
原生的jdbc代码,创建链接和处理异常,以及关闭链接等都是一样的操作。可以将其提取出来成为一个模板。
5.3.2 使用JDBC模板
spring将数据访问的样板式代码提取到模板类中。Spring为JDBC提供了3个模板类使用:
- JdbcTemplate:最基本的Spring JDBC模板,这个模板支持最简单的JDBC数据库访问功能以及简单的索引参数查询。
- NameParameterJDbcTeplate:使用该模板类执行查询时,可以将查询值以命名参数的形式绑定带SQL中,而不是见到你的索引参数。
- SimpleJdbcTemplate:该模板类利用Java5的一些特性,如自定装箱、泛型以及可变参数列表来简化JDBC模板使用;
使用SimpleJdbcTemplate访问数据库(写完之后发现Spring3.0.0左右的版本有SimpleJdbcTemplate这个类,而我之前一直用的4.2.9这个版本,于是,为了配合这本书,又换成了老版本,技术更新的快,这本书老了):
用法不难:
首先数据库表(创建如下的表,我用的mysql,数据随便写):
需要下面几个类:
model:
1 package com.springinaction.model; 2 3 /** 4 * 5 * @ClassName: User 6 * @Description: 用户的model类 7 * @author mao 8 * @date 2017年3月29日 下午11:57:39 9 * 10 */ 11 public class User { 12 13 private int id; 14 private String userName; 15 private String birthday; 16 private String sex; 17 private String address; 18 19 public User() { 20 21 } 22 23 public int getId() { 24 return id; 25 } 26 27 public void setId(int id) { 28 this.id = id; 29 } 30 31 public String getUserName() { 32 return userName; 33 } 34 35 public void setUserName(String userName) { 36 this.userName = userName; 37 } 38 39 public String getBirthday() { 40 return birthday; 41 } 42 43 public void setBirthday(String birthday) { 44 this.birthday = birthday; 45 } 46 47 public String getSex() { 48 return sex; 49 } 50 51 public void setSex(String sex) { 52 this.sex = sex; 53 } 54 55 public String getAddress() { 56 return address; 57 } 58 59 public void setAddress(String address) { 60 this.address = address; 61 } 62 63 @Override 64 public String toString() { 65 return "User [id=" + id + ", userName=" + userName + ", birthday=" 66 + birthday + ", sex=" + sex + ", address=" + address + "]"; 67 } 68 69 70 71 72 73 }
dao接口:
1 package com.springinaction.dao; 2 3 import com.springinaction.model.User; 4 5 /** 6 * 7 * @ClassName: UserDao 8 * @Description: 用户dao的接口 9 * @author mao 10 * @date 2017年3月29日 下午11:58:50 11 * 12 */ 13 public interface UserDao { 14 15 public void addUser(User user); 16 17 }
dao的实现类(可以看到里面的东西都过时了,被划了横线):
1 package com.springinaction.dao.impl; 2 3 import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; 4 5 import com.springinaction.dao.UserDao; 6 import com.springinaction.model.User; 7 8 /** 9 * 10 * @ClassName: JdbcUserDao 11 * @Description: UserDao的实现类 12 * @author mao 13 * @date 2017年3月29日 下午11:59:45 14 * 15 */ 16 public class JdbcUserDao implements UserDao{ 17 18 //过时了都,4.2.9版本都没有这个类,哎,这书太老了 19 private SimpleJdbcTemplate jdbcTemplate; 20 21 public void setJdbcTemplate(SimpleJdbcTemplate jdbcTemplate) { 22 this.jdbcTemplate = jdbcTemplate; 23 } 24 25 public void addUser(User user){ 26 27 jdbcTemplate.update("update user set username=? where id=?", 28 user.getUserName(), 29 user.getId() 30 ); 31 } 32 }
springbean.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:context="http://www.springframework.org/schema/context" 5 xmlns:aop="http://www.springframework.org/schema/aop" 6 xmlns:p="http://www.springframework.org/schema/p" 7 xsi:schemaLocation="http://www.springframework.org/schema/beans 8 http://www.springframework.org/schema/beans/spring-beans-4.0.xsd 9 http://www.springframework.org/schema/context 10 http://www.springframework.org/schema/context/spring-context-4.0.xsd 11 http://www.springframework.org/schema/aop 12 http://www.springframework.org/schema/aop/spring-aop-4.0.xsd"> 13 14 15 <!--注解形式的 组件扫描 --> 16 <context:component-scan 17 base-package="com.springinaction.springidol"></context:component-scan> 18 19 20 <!--基于dbcp 配置数据源 --> 21 <!-- <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> 22 <property name="driverClassName" value="com.mysql.jdbc.Driver"></property> 23 <property name="url" value="jdbc:mysql://localhost:3306/test"></property> 24 <property name="username" value="root"></property> 25 <property name="password" value="mysql"></property> 26 <property name="initialSize" value="5"></property> 27 <property name="maxActive" value="10"></property> 28 </bean> --> 29 30 <!--基于dbcp 配置数据源 --> 31 <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> 32 <property name="driverClassName" value="com.mysql.jdbc.Driver"></property> 33 <property name="url" value="jdbc:mysql://localhost:3306/test"></property> 34 <property name="username" value="root"></property> 35 <property name="password" value="mysql"></property> 36 <!-- <property name="initialSize" value="5"></property> 37 <property name="maxActive" value="10"></property> --> 38 </bean> 39 40 <!-- 使用SimpleJdbcTemplate --> 41 <bean id="jdbcTemplate" class="org.springframework.jdbc.core.simple.SimpleJdbcTemplate"> 42 <constructor-arg ref="dataSource"/> 43 </bean> 44 45 <!-- dao层 --> 46 <bean id="jdbcUserDao" class="com.springinaction.dao.impl.JdbcUserDao"> 47 <property name="jdbcTemplate" ref="jdbcTemplate"></property> 48 </bean> 49 50 </beans>
测试代码:
1 //测试SimpleJdbcTemplate 2 //测试spring数据源配置 3 @Test 4 public void testTemplate() throws Exception { 5 6 UserDao userDao = (UserDao)ac.getBean("jdbcUserDao"); 7 8 User user = new User(); 9 user.setId(1); 10 user.setUserName("测试用户"); 11 userDao.addUser(user); 12 13 14 }
测试是是成功的,整个过程也可以用注解扫面的方式,不是很难,就是过时了;