1. Spring对jdbc支持
Spring通过引入相关的jar包能够支持c3p0连接池,
public class App {
// 容器对象
ApplicationContext ac = new ClassPathXmlApplicationContext("cn/itcast/h_jdbc/bean.xml");
@Test
public void testApp() throws Exception {
UserDao ud = (UserDao) ac.getBean("userDao");
// ud.save();
System.out.println(ud.findById(5));
System.out.println(ud.getAll());
}
}
class UserDao {
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public void save() {
String sql = "insert into t_dept(deptName) values('test');";
jdbcTemplate.update(sql);
}
public Dept findById(int id) {
String sql = "select * from t_dept where deptId=?";
List list = jdbcTemplate.query(sql,new MyResult(), id);
return (list!=null && list.size()>0) ? list.get(0) : null;
}
public List getAll() {
String sql = "select * from t_dept";
List list = jdbcTemplate.query(sql, new MyResult());
return list;
}
class MyResult implements RowMapper{
// 如何封装一行记录
@Override
public Dept mapRow(ResultSet rs, int index) throws SQLException {
Dept dept = new Dept();
dept.setDeptId(rs.getInt("deptId"));
dept.setDeptName(rs.getString("deptName"));
return dept;
}
}
}
class Dept {
private int deptId;
private String deptName;
public int getDeptId() {
return deptId;
}
public void setDeptId(int deptId) {
this.deptId = deptId;
}
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
}
2. Spring事务管理
Spring提供了对事务控制的实现。用户如果想用Spring的声明式事务管理,只需要在配置文件中配置即可; 不想使用时直接移除配置。这个实现了对事务控制的最大程度的解耦。
Spring声明式事务管理器类:
Jdbc技术:DataSourceTransactionManager
Hibernate技术:HibernateTransactionManager
注意:一个业务的成功: 调用的service是执行成功的,意味着service中调用的所有的dao是执行成功的。 事务应该在Service层统一控制。
2.1 XML方式实现
public class App {
@Test
public void testApp() throws Exception {
//容器对象
ApplicationContext ac = new ClassPathXmlApplicationContext("cn/itcast/a_tx/bean.xml");
// 模拟数据
Dept dept = new Dept();
dept.setDeptName("测试: 开发部");
DeptService deptService = (DeptService) ac.getBean("deptService");
deptService.save(dept);
}
}
class DeptService {
// 容器注入dao对象
private DeptDao deptDao;
public void setDeptDao(DeptDao deptDao) {
this.deptDao = deptDao;
}
/*
* 事务控制?
*/
public void save(Dept dept){
// 第一次调用
deptDao.save(dept);
int i = 1/0; // 异常: 整个Service.save()执行成功的要回滚
// 第二次调用
deptDao.save(dept);
}
}
class DeptDao {
// 容器注入JdbcTemplate对象
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public void save(Dept dept){
String sql = "insert into t_dept (deptName) values(?)";
jdbcTemplate.update(sql,dept.getDeptName());
}
}
class Dept {
private int deptId;
private String deptName;
public int getDeptId() {
return deptId;
}
public void setDeptId(int deptId) {
this.deptId = deptId;
}
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
}
2.2 注解方式实现
使用注解实现Spring的声明式事务管理,更加简单!
步骤:
1) 必须引入Aop相关的jar文件
2) bean.xml中指定注解方式实现声明式事务管理以及应用的事务管理器类
3)在需要添加事务控制的地方,写上: @Transactional
@Transactional注解:
1)应用事务的注解
2)定义到方法上: 当前方法应用spring的声明式事务
3)定义到类上: 当前类的所有的方法都应用Spring声明式事务管理;
4)定义到父类上: 当执行父类的方法时候应用事务。
public class App {
@Test
public void testApp() throws Exception {
//容器对象
ApplicationContext ac = new ClassPathXmlApplicationContext("cn/itcast/b_anno/bean.xml");
// 模拟数据
Dept dept = new Dept();
dept.setDeptName("测试: 开发部");
DeptService deptService = (DeptService) ac.getBean("deptService");
deptService.save(dept);
}
// 了解容器的相关方法
@Test
public void testApp2() throws Exception {
//1. 根据bean.xml配置路径,创建容器对象
//ApplicationContext ac = new ClassPathXmlApplicationContext("cn/itcast/b_anno/bean.xml");
//2. 根据多个配置文件的路径,创建容器对象
//ApplicationContext ac = new ClassPathXmlApplicationContext(new String[]{});
//3. 容器对象相关方法
ApplicationContext ac =
new ClassPathXmlApplicationContext("cn/itcast/b_anno/bean.xml");
//3.1 从容器中获取指定名称的bean对象
//DeptDao deptDao = (DeptDao) ac.getBean("deptDao");
//3.2 根据类型从容器获取实例 【改类型只能在IOC中有唯一的对象,否则报错】
//DeptDao deptDao = ac.getBean(DeptDao.class);
//3.3 泛型,不需要强转
//DeptDao deptDao = ac.getBean("deptDap", DeptDao.class);
//3.4 获取容器中bean对象的数量
//int count = ac.getBeanDefinitionCount();
String[] names = ac.getBeanDefinitionNames();
System.out.println(Arrays.toString(names));
}
}
@Service
public class DeptService {
// 部门dao
@Resource
private DeptDao deptDao;
// 日志dao
@Resource
private LogDao logDao;
/*
* 事务控制?
*/
@Transactional(
readOnly = false, // 读写事务
timeout = -1, // 事务的超时时间不限制
//noRollbackFor = ArithmeticException.class, // 遇到数学异常不回滚
isolation = Isolation.DEFAULT, // 事务的隔离级别,数据库的默认
propagation = Propagation.REQUIRED // 事务的传播行为
)
public void save(Dept dept){
logDao.insertLog(); // 保存日志 【自己开启一个事务】
int i = 1/0;
deptDao.save(dept); // 保存部门
}
}
@Repository
public class DeptDao {
@Resource
private JdbcTemplate jdbcTemplate;
public void save(Dept dept){
String sql = "insert into t_dept (deptName) values(?)";
jdbcTemplate.update(sql,dept.getDeptName());
}
}
// 测试: 日志传播行为
@Repository
public class LogDao {
@Resource
private JdbcTemplate jdbcTemplate;
// 始终开启事务
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void insertLog() {
jdbcTemplate.update("insert into log_ (content) values('在保存Dept11..')");
}
}
public class Dept {
private int deptId;
private String deptName;
public int getDeptId() {
return deptId;
}
public void setDeptId(int deptId) {
this.deptId = deptId;
}
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
}
事务传播行为:
Propagation.REQUIRED
指定当前的方法必须在事务的环境下执行;
如果当前运行的方法,已经存在事务, 就会加入当前的事务;
Propagation.REQUIRED_NEW
指定当前的方法必须在事务的环境下执行;
如果当前运行的方法,已经存在事务: 事务会挂起; 会始终开启一个新的事务,执行完后; 刚才挂起的事务才继续运行。