一、回顾JDBC
1.java操作关系型数据的API。
导入相关数据库的驱动包后可以通过JDBC提供的接口来操作数据库。
2.实现JDBC的六个步骤
注册数据库驱动
获取数据库连接
获取传输器对象
传输sql执行获取结果集对象
遍历结果集获取信息
关闭资源
1 package cn.tedu.jdbc;
2
3 import java.sql.Connection;
4 import java.sql.DriverManager;
5 import java.sql.PreparedStatement;
6 import java.sql.ResultSet;
7 import java.sql.SQLException;
8
9
10 /**
11 create database springdb;
12 use springdb;
13 create table stu(id int primary key auto_increment,name varchar(255),addr varchar(255));
14 insert into stu values (null,'aaa','bj'),(null,'bbb','sh'),(null,'ccc','gz'),(null,'ddd','sh'),(null,'eee','bj');
15 */
16 public class Demo01 {
17 public static void main(String[] args){
18 Connection conn = null;
19 PreparedStatement ps = null;
20 ResultSet rs = null;
21 try {
22 //1.注册数据库驱动
23 Class.forName("com.mysql.jdbc.Driver");
24 //2.获取数据库连接
25 conn = DriverManager.getConnection("jdbc:mysql:///springdb","root","root");
26 //3.获取传输器
27 ps = conn.prepareStatement("select * from stu where id < ?");
28 ps.setInt(1, 4);
29 //4.执行sql获取结果集
30 rs = ps.executeQuery();
31 //5.遍历结果集获取结果
32 while(rs.next()){
33 String name = rs.getString("name");
34 System.out.println(name);
35 }
36 } catch (Exception e) {
37 e.printStackTrace();
38 } finally {
39 //6.关闭资源
40 if(rs!=null){
41 try {
42 rs.close();
43 } catch (SQLException e) {
44 e.printStackTrace();
45 } finally{
46 rs = null;
47 }
48 }
49 if(ps!=null){
50 try {
51 ps.close();
52 } catch (SQLException e) {
53 e.printStackTrace();
54 } finally{
55 ps = null;
56 }
57 }
58 if(conn!=null){
59 try {
60 conn.close();
61 } catch (SQLException e) {
62 e.printStackTrace();
63 } finally{
64 conn = null;
65 }
66 }
67 }
68
69 }
70 }
3.数据库连接池(数据源)
C3P0连接池
1 package cn.tedu.jdbc;
2
3 import java.beans.PropertyVetoException;
4 import java.sql.Connection;
5 import java.sql.PreparedStatement;
6 import java.sql.ResultSet;
7 import java.sql.SQLException;
8
9 import com.mchange.v2.c3p0.ComboPooledDataSource;
10
11
12 /**
13 create database springdb;
14 use springdb;
15 create table stu(id int primary key auto_increment,name varchar(255),addr varchar(255));
16 insert into stu values (null,'aaa','bj'),(null,'bbb','sh'),(null,'ccc','gz'),(null,'ddd','sh'),(null,'eee','bj');
17 */
18 public class Demo02 {
19 private static ComboPooledDataSource dataSource = new ComboPooledDataSource();
20 static{
21 try {
22 dataSource.setDriverClass("com.mysql.jdbc.Driver");
23 dataSource.setJdbcUrl("jdbc:mysql:///springdb");
24 dataSource.setUser("root");
25 dataSource.setPassword("root");
26 } catch (PropertyVetoException e) {
27 e.printStackTrace();
28 throw new RuntimeException(e);
29 }
30 }
31
32 public static void main(String[] args){
33 Connection conn = null;
34 PreparedStatement ps = null;
35 ResultSet rs = null;
36 try {
37 //1.2.从数据源中获取连接
38 conn = dataSource.getConnection();
39 //3.获取传输器
40 ps = conn.prepareStatement("select * from stu where id < ?");
41 ps.setInt(1, 4);
42 //4.执行sql获取结果集
43 rs = ps.executeQuery();
44 //5.遍历结果集获取结果
45 while(rs.next()){
46 String name = rs.getString("name");
47 System.out.println(name);
48 }
49 } catch (Exception e) {
50 e.printStackTrace();
51 } finally {
52 //6.关闭资源
53 if(rs!=null){
54 try {
55 rs.close();
56 } catch (SQLException e) {
57 e.printStackTrace();
58 } finally{
59 rs = null;
60 }
61 }
62 if(ps!=null){
63 try {
64 ps.close();
65 } catch (SQLException e) {
66 e.printStackTrace();
67 } finally{
68 ps = null;
69 }
70 }
71 if(conn!=null){
72 try {
73 conn.close();
74 } catch (SQLException e) {
75 e.printStackTrace();
76 } finally{
77 conn = null;
78 }
79 }
80 }
81
82 }
83 }
二、整合JDBC - 管理数据源
1.导入相关开发包
2.将数据源交于Spring管理
3.通过Spring获取数据源,获取连接,操作数据库
三、Spring整合JDBC - JDBC 模板类
使用模板类能够极大的简化原有JDBC的编程过程。
a.在Spring中配置JDBC模板类
b.使用JDBC模板类实现增删改查
1 /**
2 * 使用jdbc模板类 实现 delete
3 */
4 @Test
5 public void test06(){
6 JdbcTemplate jdbcTemplate = (JdbcTemplate) context.getBean("jdbcTemplate");
7 int count = jdbcTemplate.update("delete from stu where id = ?",4);
8 System.out.println("执行成功,影响到的行数为"+count);
9 }
10
11 /**
12 * 使用jdbc模板类 实现 insert
13 */
14 @Test
15 public void test05(){
16 JdbcTemplate jdbcTemplate = (JdbcTemplate) context.getBean("jdbcTemplate");
17 int count = jdbcTemplate.update("insert into stu values (null,?,?)","fff","gz");
18 System.out.println("执行成功,影响到的行数为"+count);
19 }
20
21
22 /**
23 * 使用jdbc模板类 实现 update
24 */
25 @Test
26 public void test04(){
27 JdbcTemplate jdbcTemplate = (JdbcTemplate) context.getBean("jdbcTemplate");
28 int count = jdbcTemplate.update("update stu set addr = ? where id = ?", "sz",3);
29 System.out.println("执行成功,影响到的行数为"+count);
30 }
31
32 /**
33 * 使用jdbc模板类 实现 query
34 */
35 @Test
36 public void test03(){
37 JdbcTemplate jdbcTemplate = (JdbcTemplate) context.getBean("jdbcTemplate");
38 SqlRowSet rs = jdbcTemplate.queryForRowSet("select * from stu where id < ?" ,4);
39 while(rs.next()){
40 String name = rs.getString("name");
41 System.out.println(name);
42 }
43 }
44
45 /**
46 * 使用jdbc模板类 实现 query
47 */
48 @Test
49 public void test02(){
50 JdbcTemplate jdbcTemplate = (JdbcTemplate) context.getBean("jdbcTemplate");
51 List<Map<String,Object>> list = jdbcTemplate.queryForList("select * from stu where id < ?",4);
52 System.out.println(list);
53 }
3.使用RowMapper封装bean
RowMapper接口定义了对象到列的映射关系,可以帮助我们在查询时自动封装bean。
1 package cn.tedu.spring.domain;
2
3 import java.sql.ResultSet;
4 import java.sql.SQLException;
5
6 import org.springframework.jdbc.core.RowMapper;
7
8 public class UserRowMapper implements RowMapper<User> {
9
10 @Override
11 public User mapRow(ResultSet rs, int rowNum) throws SQLException {
12 User user = new User();
13 user.setId(rs.getInt(1));
14 user.setName(rs.getString(2));
15 user.setAddr(rs.getString(3));
16 return user;
17 }
18
19 }
1 /** 2 * 使用jdbc模板类 使用RowMapper 3 */ 4 @Test 5 public void test08(){ 6 JdbcTemplate jdbcTemplate = (JdbcTemplate) context.getBean("jdbcTemplate"); 7 User user = jdbcTemplate.queryForObject("select * from stu where id = ?",new UserRowMapper() ,2); 8 System.out.println(user); 9 } 10 /** 11 * 使用jdbc模板类 实现单条query 12 */ 13 @Test 14 public void test09(){ 15 JdbcTemplate jdbcTemplate = (JdbcTemplate) context.getBean("jdbcTemplate"); 16 List<User> list = jdbcTemplate.query("select * from stu", new UserRowMapper()); 17 System.out.println(list); 18 }
4.使用BeanPropertyRowMapper自动进行映射
BeanPropertyRowMapper内部可以指定类进行反射(内省)来获知类内部的属性信息,自动映射到表的列。使用它一定要注意,类的属性名要和对应表的列名必须对应的上,否则属性无法自动映射。BeanPropertyRowMapper底层通过反射(内省)来实现,相对于之前自己写的RowwMapper效率比较低。
1 /**
2 * 使用jdbc模板类 实现单条query
3 */
4 @Test
5 public void test10(){
6 JdbcTemplate jdbcTemplate = (JdbcTemplate) context.getBean("jdbcTemplate");
7 List<User> list = jdbcTemplate.query(
8 "select * from stu",
9 new BeanPropertyRowMapper(User.class));
10 System.out.println(list);
11 }
四、Spring整合JDBC - 声明式事务处理
Spring中提供了内置的事务处理机制,称之为声明式事务处理。
1.创建项目,模拟MVC三层架构
2.在配置文件中导入相关约束
3.配置事务管理器
4.配置事务切面
5.配置事务通知
6.配置关系图
7.事务管理策略
异常的种类:
java.lang.Throwable
|-Exception
|-RuntimeException
|-其他Exception
|-Error
spring内置的事务策略,只在底层抛出的异常是运行时异常时,才会回滚,其他异常不回滚,留给用户手动处理。
也可以在配置中指定在原有规则的基础上,哪些异常额外回滚或不回滚:
配置成如下形式,可以实现任意异常都自动回滚:
8.注意:如果在一个业务逻辑中,需要有多步不同表的操作,此时应该在service层完成对不同表的操作,一次保证多步操作处于同一个事务中,切勿将业务代码在web层中调用Service来实现,虽然正常情况下也可以完成功能,但一旦出问题,很可能只有部分操作回滚,数据出现问题。
出现这种问题,不是事务管理机制的问题,而是开发者将业务逻辑错误的在web层中进行了实现,所以切记,web层只负责和用户交互和业务逻辑的调用,不进行任何业务逻辑的处理,任何业务逻辑都在service层中进行。
五、声明式事务处理 - 注解方式
1.开启事务注解配置
2.在方法上通过注解开启事务
即可以标注在接口上,也可以标注在实现类上,理论上应该表在接口上,实现面向接口编程,但实际开发中为了方便也有人写在实现类上。
也可以在类上使用此接口,此时类中所有方法都会有事务
当在类上开启了事务后,可以此类的方法中使用如下方法,控制某个方法没有事务
通过注解控制事务时,和配置文件方式控制事务相同的是,默认只有运行时异常才会回滚,非运行时异常不回滚,此时可以通过如下注解选项额外配置 ,哪些异常需要回滚,哪些不需要。
六、扩展案例
**扩展案例:缓存的使用 - 通过AOP实现为查询操作增加缓存机制
1 @Component 2 @Aspect 3 public class CatchAspect { 4 /** 5 * 使用Map实现的缓存 6 * 只会增加不会减少 7 * 没有超时时间,不管过了多久都使用历史缓存 8 * 没有存储优化 9 */ 10 private Map<Integer,User> map = new HashMap<Integer,User>(); 11 12 @Around("execution(* cn.tedu.spring.service.*.queryUser(..))") 13 public User around(ProceedingJoinPoint jp) throws Throwable{ 14 int i = (Integer) jp.getArgs()[0]; 15 if(map.containsKey(i)){ 16 System.out.println("使用缓存查询。。。"); 17 //有缓存 18 return map.get(i); 19 }else{ 20 System.out.println("使用数据库查询。。。"); 21 //没缓存 22 User user = (User) jp.proceed(); 23 map.put(user.getId(), user); 24 return user; 25 } 26 } 27 }