一、回顾JDBC
1.java操作关系型数据的API。
导入相关数据库的驱动包后可以通过JDBC提供的接口来操作数据库。
2.实现JDBC的六个步骤
注册数据库驱动
获取数据库连接
获取传输器对象
传输sql执行获取结果集对象
遍历结果集获取信息
关闭资源
1 packagecn.tedu.jdbc;2
3 importjava.sql.Connection;4 importjava.sql.DriverManager;5 importjava.sql.PreparedStatement;6 importjava.sql.ResultSet;7 importjava.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 classDemo01 {17 public static voidmain(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 packagecn.tedu.jdbc;2
3 importjava.beans.PropertyVetoException;4 importjava.sql.Connection;5 importjava.sql.PreparedStatement;6 importjava.sql.ResultSet;7 importjava.sql.SQLException;8
9 importcom.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 classDemo02 {19 private static ComboPooledDataSource dataSource = newComboPooledDataSource();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 newRuntimeException(e);29 }30 }31
32 public static voidmain(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模板类 实现 delete3 */
4 @Test5 public voidtest06(){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模板类 实现 insert13 */
14 @Test15 public voidtest05(){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模板类 实现 update24 */
25 @Test26 public voidtest04(){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模板类 实现 query34 */
35 @Test36 public voidtest03(){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模板类 实现 query47 */
48 @Test49 public voidtest02(){50 JdbcTemplate jdbcTemplate = (JdbcTemplate) context.getBean("jdbcTemplate");51 List> list = jdbcTemplate.queryForList("select * from stu where id < ?",4);52 System.out.println(list);53 }
3.使用RowMapper封装bean
RowMapper接口定义了对象到列的映射关系,可以帮助我们在查询时自动封装bean。
1 packagecn.tedu.spring.domain;2
3 importjava.sql.ResultSet;4 importjava.sql.SQLException;5
6 importorg.springframework.jdbc.core.RowMapper;7
8 public class UserRowMapper implements RowMapper{9
10 @Override11 public User mapRow(ResultSet rs, int rowNum) throwsSQLException {12 User user = newUser();13 user.setId(rs.getInt(1));14 user.setName(rs.getString(2));15 user.setAddr(rs.getString(3));16 returnuser;17 }18
19 }
1 /** 2 * 使用jdbc模板类 使用RowMapper3 */ 4 @Test5 public voidtest08(){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模板类 实现单条query12 */ 13 @Test14 public voidtest09(){15 JdbcTemplate jdbcTemplate = (JdbcTemplate) context.getBean("jdbcTemplate");16 List list = jdbcTemplate.query("select * from stu", newUserRowMapper());17 System.out.println(list);18 }
4.使用BeanPropertyRowMapper自动进行映射
BeanPropertyRowMapper内部可以指定类进行反射(内省)来获知类内部的属性信息,自动映射到表的列。使用它一定要注意,类的属性名要和对应表的列名必须对应的上,否则属性无法自动映射。BeanPropertyRowMapper底层通过反射(内省)来实现,相对于之前自己写的RowwMapper效率比较低。
1 /**
2 * 使用jdbc模板类 实现单条query3 */
4 @Test5 public voidtest10(){6 JdbcTemplate jdbcTemplate = (JdbcTemplate) context.getBean("jdbcTemplate");7 List 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 @Component2 @Aspect3 public classCatchAspect {4 /**
5 * 使用Map实现的缓存6 * 只会增加不会减少7 * 没有超时时间,不管过了多久都使用历史缓存8 * 没有存储优化9 */
10 private Map map = new HashMap();11
12 @Around("execution(* cn.tedu.spring.service.*.queryUser(..))")13 public User around(ProceedingJoinPoint jp) throwsThrowable{14 int i = (Integer) jp.getArgs()[0];15 if(map.containsKey(i)){16 System.out.println("使用缓存查询。。。");17 //有缓存
18 returnmap.get(i);19 }else{20 System.out.println("使用数据库查询。。。");21 //没缓存
22 User user =(User) jp.proceed();23 map.put(user.getId(), user);24 returnuser;25 }26 }27 }