Java第三阶段之SpringAOP、DAO、事务

第三章 Spring之AOP详解

第一节 AOP简介

AOP 简介: 面向切面编程(也叫面向方面编程):Aspect Oriented Programming(AOP),是软件开发中的一个热点,也是 Spring 框架中的一个重要内容。利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度 降低,提高程序的可重用性,同时提高了开发的效率。 主要的功能是:日志记录,性能统计,安全控制,事务处理,异常处理等等。
将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。

第二节 SpringAOP实例

1.前置通知
可以获取调用的类名,方法名和传入的参数
2.后置通知
3.环绕通知
一般只用一个,用了环绕通知,前置和后置通知就可不用
4.返回通知(很少用)
5.异常通知
新建项目Spring403
->新建com.java1234.service
StudentService.java

package com.java1234.service;

public interface StudentService {

	public void addStudent(String name);
}

->新建com.java1234.service.impl
StudentServiceImpl.java

package com.java1234.service.impl;

import com.java1234.service.StudentService;

public class StudentServiceImpl implements StudentService{

	@Override
	public void addStudent(String name) {
	//写上我们的业务逻辑
		System.out.println("添加学生"+name);
	}

}

->beans.xml

<bean id="studentService" class="com.java1234.service.impl.StudentServiceImpl"></bean>

->T.java

package com.java1234.test;

import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.java1234.service.StudentService;


public class T {

	private ApplicationContext ac;

	@Before
	public void setUp() throws Exception {
		ac=new ClassPathXmlApplicationContext("beans.xml");
	}

	@Test
	public void test1() {
		StudentService studentService=(StudentService)ac.getBean("studentService");
		studentService.addStudent("张三");
	} 
}

->启动程序
控制台上打印出“添加学生张三”
现在有一个需求,需要做一个日志记录
不是按照传统的一条直线的写代码
->com.java1234.service.impl
StudentServiceImpl.java

	public void addStudent(String name) {    
		System.out.println("开始添加学生"+name);
		System.out.println("添加学生"+name);
		System.out.println("完成学生"+name+"的添加");
	}

以前才是这样写的,按照顺序写下来
控制台上打印出
开始添加学生张三
添加学生张三
完成学生张三的添加
但是现在我们不想要日志代码侵入正常的业务逻辑代码,要用AOP来解决,用Spring把日志代码切进去
新建项目Spring403-02
->导入额外的几个与AOP有关的包
aopaliance.jar
aspectjweaver-1.6.6.jar
spring-aspects-4.0.6.RELEASE.jar
在这里插入图片描述
->新建com.java1234.advice
StudentServiceAspect.java

package com.java1234.advice;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

public class StudentServiceAspect {
	//	前置通知
	public void doBefore(JoinPoint jp){
		System.out.println("开始添加学生");
	}
	
}

->beans.xml
// 引入下面这几个才能用xmlns:aop=“http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd

<?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:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
	
	<bean id="studentServiceAspect" class="com.java1234.advice.StudentServiceAspect"></bean>
	
	<bean id="studentService" class="com.java1234.service.impl.StudentServiceImpl"></bean>
	
	<aop:config>
		//首先定义一个切面
		<aop:aspect id="studentServiceAspect" ref="studentServiceAspect">
			//定义切点,用到了表达式,来匹配addStudent这个方法,即我们的业务逻辑部分的代码
			<aop:pointcut expression="execution(* com.java1234.service.*.*(..))" id="businessService"/>
			//定义前置通知
			<aop:before method="doBefore" pointcut-ref="businessService"/>
			
		</aop:aspect> 
	</aop:config>
</beans>

->执行过程
让我们执行addStudent的方法时,通过配置before,去执行doBefore方法
->T.java

package com.java1234.test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.java1234.service.StudentService;


public class T {

	public static void main(String[] args) {
		ApplicationContext ac=new ClassPathXmlApplicationContext("beans.xml");
		StudentService studentService=(StudentService)ac.getBean("studentService");
		studentService.addStudent("张三");
		
	}
	

}

->执行结果:
开始添加学生
添加学生张三

以上只是日志打印出了一句话,能不能在日志中获取类名方法名输入参数呀
通过joinpoint可以获取到
->StudentServiceAspect .java

public void doBefore(JoinPoint jp){
		System.out.println("类名:"+jp.getTarget().getClass().getName());
		System.out.println("方法名:"+jp.getSignature().getName());
		System.out.println("开始添加学生:"+jp.getArgs()[0]);
	}

->执行结果
类名:com.java1234.service.impl.StudentServiceImpl
方法名:addStudent
开始添加学生:张三
添加学生张三

以上我们讲解了前置,再讲一个后置通知
以下都是在原先的代码中添加上方法、配置
->StudentServiceAspect .java

public void doAfter(JoinPoint jp){
    		System.out.println("类名:"+jp.getTarget().getClass().getName());
    		System.out.println("方法名:"+jp.getSignature().getName());
    		System.out.println("学生添加完成:"+jp.getArgs()[0]);
    	}

->beans.xml

		//定义后置通知
    	<aop:after method="doAfter" pointcut-ref="businessService"/>

->执行结果
类名:com.java1234.service.impl.StudentServiceImpl
方法名:addStudent
开始添加学生:张三
添加学生张三
类名:com.java1234.service.impl.StudentServiceImpl
方法名:addStudent
学生添加完成:张三

以上我们讲解了前置、后置通知,再讲一个环绕
以下都是在原先的代码中添加上方法、配置
环绕方法是有返回值的,参数也不一样
->StudentServiceAspect .java

	public Object doAround(ProceedingJoinPoint pjp) throws Throwable{
		System.out.println("添加学生前");
		Object retVal=pjp.proceed();
		System.out.println(retVal);
		System.out.println("添加学生后");
		return retVal;
	}

->StudentServiceImpl.java

package com.java1234.service.impl;

import com.java1234.service.StudentService;

public class StudentServiceImpl implements StudentService{

	@Override
	public String addStudent(String name) {
		System.out.println("添加学生"+name);
		return name;
	}

}

->beans.xml

//定义环绕通知
<aop:around method="doAround" pointcut-ref="businessService"/>

->执行结果
类名:com.java1234.service.impl.StudentServiceImpl
方法名:addStudent
开始添加学生:张三
添加学生前
添加学生张三
张三
添加学生后
类名:com.java1234.service.impl.StudentServiceImpl
方法名:addStudent
学生添加完成:张三
发现环绕通知比前置后置通知的优先级要低
但是用了环绕通知、前置后置就不需要了

返回通知
->StudentServiceAspect .java

	public void doAfterReturning(JoinPoint jp){
		System.out.println("返回通知");
	}

->beans.xml

<aop:after-returning method="doAfterReturning" pointcut-ref="businessService"/>

->执行结果
类名:com.java1234.service.impl.StudentServiceImpl
方法名:addStudent
开始添加学生:张三
添加学生前
添加学生张三
返回通知
null
添加学生后
类名:com.java1234.service.impl.StudentServiceImpl
方法名:addStudent
学生添加完成:张三

异常通知
->StudentServiceImpl.java

package com.java1234.service.impl;

import com.java1234.service.StudentService;

public class StudentServiceImpl implements StudentService{

	@Override
	public void addStudent(String name) {  
		System.out.println("添加学生"+name);
		System.out.println(1/0);
	}

}

->StudentServiceAspect .java

	public void doAfterThrowing(JoinPoint jp,Throwable ex){
		System.out.println("异常通知");
		System.out.println("异常信息:"+ex.getMessage());
	}

->beans.xml

<aop:after-throwing method="doAfterThrowing" pointcut-ref="businessService" throwing="ex"/>

->执行结果
类名:com.java1234.service.impl.StudentServiceImpl
方法名:addStudent
开始添加学生:张三
添加学生前
添加学生张三
异常通知
异常信息:/by zero
类名:com.java1234.service.impl.StudentServiceImpl
方法名:addStudent
学生添加完成:张三

第四章 Spring对DAO的支持

第一节 Spring对JDBC的支持

JDBC是最原始的连接数据库的一种操作
1.配置数据源dbcp;
2.使用JdbcTemplate;
3.JdbcDaoSupport的使用;
daoimpl类不用写jdbcTemplate实例,直接设DataSource,getJdbcTemplate()即可.
4.NamedParameterJdbcTemplate的使用;支持命名参数变量;
org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate
MapSqlParameterSource接受输入参数。

1.配置数据源dbcp;

2.使用JdbcTemplate;

新建项目Spring404
在这里插入图片描述
->新建文件夹dbcp,导入包
commons-dbcp-1.4
commons-pool
->新建属性文件jdbc.properties
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/db_spring
jdbc.username=root
jdbc.password=123456
->新建数据库db_spring
新建表t_student( )
->引入jdbctemplate所用的jar包到spring包中
spring-jdbc-4.0.6.RELEASE.jar
spring-tx-4.0.6.RELEASE.jar
->先定义数据源
beans.xml中添加与数据源有关的包
xmlns:context=“http://www.springframework.org/schema/context
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
beans.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:aop="http://www.springframework.org/schema/aop"
    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/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
    //定义数据源
	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
	//dbcp的数据源连接池
        <property name="driverClassName" value="${jdbc.driverClassName}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
    
	<context:property-placeholder location="jdbc.properties"/>
    
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    	<property name="dataSource" ref="dataSource"></property>
    </bean>

	
</beans>

->新建com.java1234.model
Student.java

package com.java1234.model;

public class Student {
	private int id;
	private String name;
	private int age;

	public Student() {
		super();
		// TODO Auto-generated constructor stub
	}

	public Student(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}

	public Student(int id, String name, int age) {
		super();
		this.id = id;
		this.name = name;
		this.age = age;
	}

	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}

	@Override
	public String toString() {
		return "Student [id=" + id + ", name=" + name + ", age=" + age + "]";
	}
}

->新建com.java1234.dao
StudentDao.java

package com.java1234.dao;

import java.util.List;

import com.java1234.model.Student;

public interface StudentDao {

	public int addStudent(Student student);
	
	public int updateStudent(Student student);
	
	public int deleteStudent(int id);
	
	public List<Student> findStudents();
}

->com.java1234.dao.impl
StudentDaoImpl.java

package com.java1234.dao.impl;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowCallbackHandler;

import com.java1234.dao.StudentDao;
import com.java1234.model.Student;

public class StudentDaoImpl implements StudentDao{
	//将jdbcTemplate作为属性。后面的bean中也作为属性
	private JdbcTemplate jdbcTemplate;
	
	public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}
	
	//用jdbcTemplate来实现以下操作
	@Override
	public int addStudent(Student student) {
		String sql="insert into t_student values(null,?,?)";
		Object []params=new Object[]{student.getName(),student.getAge()};
		return jdbcTemplate.update(sql,params);
	}

	@Override
	public int updateStudent(Student student) {
		String sql="update t_student set name=?,age=? where id=?";
		Object []params=new Object[]{student.getName(),student.getAge(),student.getId()};
		return jdbcTemplate.update(sql,params);
	}

	@Override
	public int deleteStudent(int id) {
		String sql="delete from t_student where id=?";
		Object []params=new Object[]{id};
		return jdbcTemplate.update(sql,params);
	}

	@Override
	public List<Student> findStudents() {
		String sql="select * from t_student";
		final List<Student> studentList=new ArrayList<Student>();
		jdbcTemplate.query(sql, new RowCallbackHandler(){

			@Override
			public void processRow(ResultSet rs) throws SQLException {
				Student student=new Student();
				student.setId(rs.getInt("id"));
				student.setName(rs.getString("name"));
				student.setAge(rs.getInt("age"));
				studentList.add(student);
			}
			
		});
		return studentList;
	}

}

->新建com.java1234.service
StudentService.java

package com.java1234.service;

import java.util.List;

import com.java1234.model.Student;

public interface StudentService {

	public int addStudent(Student student);
	
	public int updateStudent(Student student);
	
	public int deleteStudent(int id);
	
	public List<Student> findStudents();
}

->新建com.java1234.service.impl
StudentServiceImpl.java

package com.java1234.service.impl;

import java.util.List;

import com.java1234.dao.StudentDao;
import com.java1234.model.Student;
import com.java1234.service.StudentService;

public class StudentServiceImpl implements StudentService{
	//将studentDao作为属性在后面bean中也作为属性注入
	private StudentDao studentDao;
	
	public void setStudentDao(StudentDao studentDao) {
		this.studentDao = studentDao;
	}

	@Override
	public int addStudent(Student student) {
		return studentDao.addStudent(student);
	}

	@Override
	public int updateStudent(Student student) {
		return studentDao.updateStudent(student);
	}

	@Override
	public int deleteStudent(int id) {
		return studentDao.deleteStudent(id);
	}

	@Override
	public List<Student> findStudents() {
		return studentDao.findStudents();
	}

}

->新建com.java1234.test
T.java

package com.java1234.test;

import java.util.List;

import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.java1234.model.Student;
import com.java1234.service.StudentService;


public class T {

	private ApplicationContext ac;

	@Before
	public void setUp() throws Exception {
		ac=new ClassPathXmlApplicationContext("beans.xml");
	}

	@Test
	public void addStudent() {
		StudentService studentService=(StudentService)ac.getBean("studentService");
		int addNums=studentService.addStudent(new Student("王五", 1));
		if(addNums==1){
			System.out.println("添加成功");
		}
	}
	
	@Test
	public void updateStudent() {
		StudentService studentService=(StudentService)ac.getBean("studentService");
		int updateNums=studentService.updateStudent(new Student(8,"王五2", 2));
		if(updateNums==1){
			System.out.println("更新成功");
		}
	}
	
	@Test
	public void deleteStudent() {
		StudentService studentService=(StudentService)ac.getBean("studentService");
		int deleteNums=studentService.deleteStudent(8);
		if(deleteNums==1){
			System.out.println("删除成功");
		}
	}
	
	@Test
	public void findStudents() {
		StudentService studentService=(StudentService)ac.getBean("studentService");
		List<Student> studentList=studentService.findStudents();
		for(Student student:studentList){
			System.out.println(student);
		}
	}
	
	

}

->beans.xml

	//studentDao,注入jdbcTemplate
	<bean id="studentDao" class="com.java1234.dao.impl.StudentDaoImpl">
		<property name="jdbcTemplate" ref="jdbcTemplate"></property>
	</bean> 
	//studentService,注入studentDao
	<bean id="studentService" class="com.java1234.service.impl.StudentServiceImpl">
		<property name="studentDao" ref="studentDao"></property>
	</bean> 

->执行程序
addStudent JunitTest 控制台上输出:添加成功
数据库中多了一条记录(0,王五,1)
updateStudent JunitTest 控制台上输出:更新成功
数据库中改成一条记录(8,王五2,2)
deleteStudent JunitTest 控制台上输出:删除成功
数据库中删除一条记录(8,王五2,2)
findStudents JunitTest 控制台上输出:查询成功
从数据库中遍历出记录
Student[id=2,name=张三,age=12]

3.JdbcDaoSupport的使用;

daoimpl类不用写jdbcTemplate实例,直接设DataSource,getJdbcTemplate()即可.
新建项目Spring404-02
->com.java1234.dao
StudentDao.java

package com.java1234.dao;

import java.util.List;

import com.java1234.model.Student;

public interface StudentDao {

	public int addStudent(Student student);
	
	public int updateStudent(Student student);
	
	public int deleteStudent(int id);
	
	public List<Student> findStudents();
}

->com.java1234.dao,impl
StudentDaoImpl.java

package com.java1234.dao.impl;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowCallbackHandler;
import org.springframework.jdbc.core.support.JdbcDaoSupport;

import com.java1234.dao.StudentDao;
import com.java1234.model.Student;

//extends JdbcDaoSupport
//它的源码里面有jdbctemplate就不需要我们自己定义了
public class StudentDaoImpl extends JdbcDaoSupport implements StudentDao{

	@Override
	public int addStudent(Student student) {
		String sql="insert into t_student values(null,?,?)";
		Object []params=new Object[]{student.getName(),student.getAge()};
		return this.getJdbcTemplate().update(sql,params);
	}

	@Override
	public int updateStudent(Student student) {
		String sql="update t_student set name=?,age=? where id=?";
		Object []params=new Object[]{student.getName(),student.getAge(),student.getId()};
		return this.getJdbcTemplate().update(sql,params);
	}

	@Override
	public int deleteStudent(int id) {
		String sql="delete from t_student where id=?";
		Object []params=new Object[]{id};
		return this.getJdbcTemplate().update(sql,params);
	}

	@Override
	public List<Student> findStudents() {
		String sql="select * from t_student";
		final List<Student> studentList=new ArrayList<Student>();
		this.getJdbcTemplate().query(sql, new RowCallbackHandler(){

			@Override
			public void processRow(ResultSet rs) throws SQLException {
				Student student=new Student();
				student.setId(rs.getInt("id"));
				student.setName(rs.getString("name"));
				student.setAge(rs.getInt("age"));
				studentList.add(student);
			}
			
		});
		return studentList;
	}

}

->beans.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:aop="http://www.springframework.org/schema/aop"
    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/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
        
	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="${jdbc.driverClassName}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
    
	<context:property-placeholder location="jdbc.properties"/>
    
 
	
	<bean id="studentDao" class="com.java1234.dao.impl.StudentDaoImpl">
		<property name="dataSource" ref="dataSource"></property>
	</bean> 
	
	<bean id="studentService" class="com.java1234.service.impl.StudentServiceImpl">
		<property name="studentDao" ref="studentDao"></property>
	</bean> 
	
</beans>

->T.java

package com.java1234.test;

import java.util.List;

import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.java1234.model.Student;
import com.java1234.service.StudentService;


public class T {

	private ApplicationContext ac;

	@Before
	public void setUp() throws Exception {
		ac=new ClassPathXmlApplicationContext("beans.xml");
	}

	@Test
	public void addStudent() {
		StudentService studentService=(StudentService)ac.getBean("studentService");
		int addNums=studentService.addStudent(new Student("王五", 1));
		if(addNums==1){
			System.out.println("添加成功");
		}
	}
	
	@Test
	public void updateStudent() {
		StudentService studentService=(StudentService)ac.getBean("studentService");
		int updateNums=studentService.updateStudent(new Student(10,"王五2", 2));
		if(updateNums==1){
			System.out.println("更新成功");
		}
	}
	
	@Test
	public void deleteStudent() {
		StudentService studentService=(StudentService)ac.getBean("studentService");
		int deleteNums=studentService.deleteStudent(10);
		if(deleteNums==1){
			System.out.println("删除成功");
		}
	}
	
	@Test
	public void findStudents() {
		StudentService studentService=(StudentService)ac.getBean("studentService");
		List<Student> studentList=studentService.findStudents();
		for(Student student:studentList){
			System.out.println(student);
		}
	}
	
	

}

->运行结果
添加成功
更新成功
删除成功
查询成功
jdbcsupport方便了一些

4.NamedParameterJdbcTemplate的使用;支持命名参数变量;

新建项目Spring404-03
->beans.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:aop="http://www.springframework.org/schema/aop"
    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/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
        
	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="${jdbc.driverClassName}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
    
	<context:property-placeholder location="jdbc.properties"/>
    //org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate
    <bean id="namedParameterJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
    	//	这里就不是属性了而是构造方法传入数据源
    	<constructor-arg ref="dataSource"></constructor-arg>
    </bean>
	
	
	<bean id="studentDao" class="com.java1234.dao.impl.StudentDaoImpl">
		<property name="namedParameterJdbcTemplate" ref="namedParameterJdbcTemplate"></property>
	</bean> 
	
	<bean id="studentService" class="com.java1234.service.impl.StudentServiceImpl">
		<property name="studentDao" ref="studentDao"></property>
	</bean> 
	
</beans>

->StudentDaoImpl.java

package com.java1234.dao.impl;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowCallbackHandler;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;

import com.java1234.dao.StudentDao;
import com.java1234.model.Student;

public class StudentDaoImpl implements StudentDao{
	//NamedParameterJdbcTemplate
	private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
	
	public void setNamedParameterJdbcTemplate(
			NamedParameterJdbcTemplate namedParameterJdbcTemplate) {
		this.namedParameterJdbcTemplate = namedParameterJdbcTemplate;
	}
	//	有了这些以后,
	@Override
	public int addStudent(Student student) {
		String sql="insert into t_student values(null,:name,:age)";
		//MapSqlParameterSource专门来放参数
		MapSqlParameterSource sps=new MapSqlParameterSource();
		sps.addValue("name", student.getName());
		sps.addValue("age", student.getAge());
		return namedParameterJdbcTemplate.update(sql,sps);
	}

	@Override
	public int updateStudent(Student student) {
		String sql="update t_student set name=:name,age=:age where id=:id";
		MapSqlParameterSource sps=new MapSqlParameterSource();
		sps.addValue("name", student.getName());
		sps.addValue("age", student.getAge());
		sps.addValue("id", student.getId());
		return namedParameterJdbcTemplate.update(sql,sps);
	}

	@Override
	public int deleteStudent(int id) {
		String sql="delete from t_student where id=:id";
		MapSqlParameterSource sps=new MapSqlParameterSource();
		sps.addValue("id", id);
		return namedParameterJdbcTemplate.update(sql,sps);
	}

	@Override
	public List<Student> findStudents() {
		String sql="select * from t_student";
		final List<Student> studentList=new ArrayList<Student>();
		namedParameterJdbcTemplate.query(sql, new RowCallbackHandler(){

			@Override
			public void processRow(ResultSet rs) throws SQLException {
				Student student=new Student();
				student.setId(rs.getInt("id"));
				student.setName(rs.getString("name"));
				student.setAge(rs.getInt("age"));
				studentList.add(student);
			}
			
		});
		return studentList;
	}

}

->执行结果
成功

第二节:Spring 对 Hibernate 的支持

后面 Spring 整合 Hibernate 的时候讲;

第五章 Spring对事务的支持

第一节 事务简介

要满足四个条件:
1.原子性
2.一致性
3.隔离性
4.持久性

第二节 编程式事务管理(用的较少,不是太好,会侵入业务代码)

Spring提供的事务模板类:org.springframework.transaction.support.TransactionTemplate
事务管理器:org.springframework.jdbc.datasource.DataSourceTransactionManager
银行转账例子
新建项目Spring405
->在数据库中建立db_bank
表t_count(id,userid,username,count)
->新建com.java1234.dao
BankDao.java

package com.java1234.dao;

public interface BankDao {

	public void inMoney(int money,int userId);
	
	public void outMoney(int money,int userId);
}

->com.java1234.dao.impl
BankDaoImpl.java

package com.java1234.dao.impl;

import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;

import com.java1234.dao.BankDao;

public class BankDaoImpl implements BankDao{

	private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
	
	
	public void setNamedParameterJdbcTemplate(
			NamedParameterJdbcTemplate namedParameterJdbcTemplate) {
		this.namedParameterJdbcTemplate = namedParameterJdbcTemplate;
	}
	
	@Override
	public void inMoney(int money, int userId) {
		// TODO Auto-generated method stub
		String sql="update t_count2 set count=count+:money where userId=:userId";
		MapSqlParameterSource sps=new MapSqlParameterSource();
		sps.addValue("money", money);
		sps.addValue("userId", userId);
		namedParameterJdbcTemplate.update(sql,sps);
	}

	@Override
	public void outMoney(int money, int userId) {
		// TODO Auto-generated method stub
		String sql="update t_count set count=count-:money where userId=:userId";
		MapSqlParameterSource sps=new MapSqlParameterSource();
		sps.addValue("money", money);
		sps.addValue("userId", userId);
		namedParameterJdbcTemplate.update(sql,sps);
	}

}

->com.java1234.service
事物层
BankService.java

package com.java1234.service;

public interface BankService {

	/**
	 * A向B转账count元
	 * @param count
	 * @param userIdA
	 * @param userIdB
	 */
	public void transferAccounts(int count,int userIdA,int userIdB);
}

->com.java1234.service.impl
BankServiceImpl.java

package com.java1234.service.impl;

import com.java1234.dao.BankDao;
import com.java1234.service.BankService;


public class BankServiceImpl implements BankService{
	//首先引入dao
	private BankDao bankDao;
	
	public void setBankDao(BankDao bankDao) {
		this.bankDao = bankDao;
	}

	@Override
	public void transferAccounts(int count,int userIdA,int userIdB) {
		// TODO Auto-generated method stub
		tbankDao.outMoney(count, userIdA);
				bankDao.inMoney(count, userIdB);	
			}
	}

}

->beans.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:aop="http://www.springframework.org/schema/aop"
    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/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
        
	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="${jdbc.driverClassName}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
    
	<context:property-placeholder location="jdbc.properties"/>
    
    <bean id="namedParameterJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
    	<constructor-arg ref="dataSource"></constructor-arg>
    </bean>
	
	
	<bean id="bankDao" class="com.java1234.dao.impl.BankDaoImpl">
		<property name="namedParameterJdbcTemplate" ref="namedParameterJdbcTemplate"></property>
	</bean> 
	
	<bean id="bankService" class="com.java1234.service.impl.BankServiceImpl">
		<property name="bankDao" ref="bankDao"></property>
	</bean> 
	
</beans>

->T.java

package com.java1234.test;

import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.java1234.service.BankService;


public class T {

	private ApplicationContext ac;

	@Before
	public void setUp() throws Exception {
		ac=new ClassPathXmlApplicationContext("beans.xml");
	}

	@Test
	public void transferAccounts() {
		BankService bankService=(BankService)ac.getBean("bankService");
		bankService.transferAccounts(50, 1, 2);
	}

}

->运行结果
转账成功
张三少了50李四多了50
->我们这边模拟一个异常
比如说,转出时没问题,转入时将String sqi="update t_count2…"设一个陷阱,t_count2根本就不存在
->运行结果
张三少了50但是李四没收到
->这时候必须加上事务,先讲编程式事务管理
->BankServiceImpl.java

package com.java1234.service.impl;

import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;

import com.java1234.dao.BankDao;
import com.java1234.service.BankService;


public class BankServiceImpl implements BankService{

	private BankDao bankDao;
	//引入TransactionTemplate
	private TransactionTemplate transactionTemplate;
	
	public void setBankDao(BankDao bankDao) {
		this.bankDao = bankDao;
	}
	public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
		this.transactionTemplate = transactionTemplate;
	}
	//要把事务
	@Override
	public void transferAccounts(final int count, final int userIdA, final int userIdB) {
		// TODO Auto-generated method stub
		//execute实现的方法体里面,写入doInTransactionWithoutResult方法
		transactionTemplate.execute(new TransactionCallbackWithoutResult() {
			
			@Override
			protected void doInTransactionWithoutResult(TransactionStatus arg0) {
				// TODO Auto-generated method stub
				bankDao.outMoney(count, userIdA);
				bankDao.inMoney(count, userIdB);				
			}
		});
	}

}

->beans.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:aop="http://www.springframework.org/schema/aop"
    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/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
        
	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="${jdbc.driverClassName}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
    //先配置事务管理器,注入数据源这个属性
    <!-- jdbc事务管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    	<property name="dataSource" ref="dataSource"></property>
    </bean>
    //注入transactionTemplate,注入属性事务管理器
    <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
    	<property name="transactionManager" ref="transactionManager"></property>
    </bean>
     
	<context:property-placeholder location="jdbc.properties"/>
    
    <bean id="namedParameterJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
    	<constructor-arg ref="dataSource"></constructor-arg>
    </bean>
	
	
	<bean id="bankDao" class="com.java1234.dao.impl.BankDaoImpl">
		<property name="namedParameterJdbcTemplate" ref="namedParameterJdbcTemplate"></property>
	</bean> 
	//在service层注入事务transactionTemplate
	<bean id="bankService" class="com.java1234.service.impl.BankServiceImpl">
		<property name="bankDao" ref="bankDao"></property>
		<property name="transactionTemplate" ref="transactionTemplate"></property>
	</bean> 
	
</beans>

->运行结果
张三没扣钱李四也没收到钱
这个编程式事务管理不太好,因为事务的代码已经入侵到业务代码中了

第三节 声明式事务管理

1.使用XML配置声明式事务(一般情况下使用)
优点:只要配置一个xml文件,所有service都可以事务管理
新建项目Spring405-02
->BankServiceImpl.java

package com.java1234.service.impl;


import com.java1234.dao.BankDao;
import com.java1234.service.BankService;


public class BankServiceImpl implements BankService{

	private BankDao bankDao;
	
	public void setBankDao(BankDao bankDao) {
		this.bankDao = bankDao;
	}
	

	@Override
	public void transferAccounts(int count, int userIdA, int userIdB) {
		// TODO Auto-generated method stub
				// TODO Auto-generated method stub
		bankDao.outMoney(count, userIdA);
		bankDao.inMoney(count, userIdB);				
	}

}

->beans.xml
首先引入命名空间
xmlns:tx=“http://www.springframework.org/schema/tx
和地址
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
然后就可以开始用了

<?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:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
        
	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="${jdbc.driverClassName}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
    
    <!-- jdbc事务管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    	<property name="dataSource" ref="dataSource"></property>
    </bean>
    
    <!-- 配置事务通知 -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
    	<tx:attributes>  
    	//切的都是方法
            <tx:method name="insert*" propagation="REQUIRED" />  
           
        </tx:attributes>  
    </tx:advice>
    
    <!-- 配置事务切面 -->
    <aop:config>
    	<!-- 配置切点 -->
    	//切的都是service层的所有方法使用表达式标准写法
    	<aop:pointcut id="serviceMethod" expression="execution(* com.java1234.service.*.*(..))" />
    	<!-- 配置事务通知 -->
    	//已经切到里面后要增加通知
    	<aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethod"/>
    </aop:config>
  
	<context:property-placeholder location="jdbc.properties"/>
    
    <bean id="namedParameterJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
    	<constructor-arg ref="dataSource"></constructor-arg>
    </bean>
	
	
	<bean id="bankDao" class="com.java1234.dao.impl.BankDaoImpl">
		<property name="namedParameterJdbcTemplate" ref="namedParameterJdbcTemplate"></property>
	</bean> 
	
	<bean id="bankService" class="com.java1234.service.impl.BankServiceImpl">
		<property name="bankDao" ref="bankDao"></property>
	</bean> 
	
</beans>

->运行结果
事务
2.使用注解配置声明式样事务
缺点:每个service都要加注解
新建项目Spring405-03
->BankServiceImpl.java

package com.java1234.service.impl;
import org.springframework.transaction.annotation.Transactional;

import com.java1234.dao.BankDao;
import com.java1234.service.BankService;
//加注解
@Transactional
public class BankServiceImpl implements BankService{

	private BankDao bankDao;
	
	public void setBankDao(BankDao bankDao) {
		this.bankDao = bankDao;
	}
	

	@Override
	public void transferAccounts(int count, int userIdA, int userIdB) {
		// TODO Auto-generated method stub
				// TODO Auto-generated method stub
		bankDao.outMoney(count, userIdA);
		bankDao.inMoney(count, userIdB);				
	}

}

->beans.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:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
        
	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="${jdbc.driverClassName}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
    
    <!-- jdbc事务管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    	<property name="dataSource" ref="dataSource"></property>
    </bean>
    //要加入这个,表明是注解,把事务管理器加进去
    <tx:annotation-driven transaction-manager="transactionManager"/>
     
	<context:property-placeholder location="jdbc.properties"/>
    
    <bean id="namedParameterJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
    	<constructor-arg ref="dataSource"></constructor-arg>
    </bean>
	
	
	<bean id="bankDao" class="com.java1234.dao.impl.BankDaoImpl">
		<property name="namedParameterJdbcTemplate" ref="namedParameterJdbcTemplate"></property>
	</bean> 
	
	<bean id="bankService" class="com.java1234.service.impl.BankServiceImpl">
		<property name="bankDao" ref="bankDao"></property>
	</bean> 
	
</beans>

->运行结果:
有效的

第四节 事务传播行为

事务传播行为:Spring 中,当一个 service 方法调用另外一个 service 方法的时候,因为每个 service 方法都有事务,这时候就出现了事务的嵌套;由此,就产生了事务传播行为; 在 Spring 中,通过配置 Propagation,来定义事务传播行为;
1PROPAGATION_REQUIRED–支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。 2PROPAGATION_SUPPORTS–支持当前事务,如果当前没有事务,就以非事务方式执行。
3PROPAGATION_MANDATORY–支持当前事务,如果当前没有事务,就抛出异常。 4PROPAGATION_REQUIRES_NEW–新建事务,如果当前存在事务,把当前事务挂起。 5PROPAGATION_NOT_SUPPORTED–以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
6PROPAGATION_NEVER–以非事务方式执行,如果当前存在事务,则抛出异常。
beanx.xml

 <tx:method name="update*" propagation="REQUIRED" />  
                <tx:method name="edit*" propagation="REQUIRED" />  
                <tx:method name="save*" propagation="REQUIRED" />  
                <tx:method name="add*" propagation="REQUIRED" />  
                <tx:method name="new*" propagation="REQUIRED" />  
                <tx:method name="set*" propagation="REQUIRED" />  
                <tx:method name="remove*" propagation="REQUIRED" />  
                <tx:method name="delete*" propagation="REQUIRED" />  
                <tx:method name="change*" propagation="REQUIRED" />  
                <tx:method name="get*" propagation="REQUIRED" read-only="true" />  
                <tx:method name="find*" propagation="REQUIRED" read-only="true" />  
                <tx:method name="load*" propagation="REQUIRED" read-only="true" />  
                <tx:method name="*" propagation="REQUIRED" read-only="true" />  






<tx:attributes> 
<tx:methodname="insert*" propagation="REQUIRED"/> <tx:methodname="update*"propagation="REQUIRED"/> 
<tx:methodname="edit*" propagation="REQUIRED"/> <tx:methodname="save*"propagation="REQUIRED"/> <tx:methodname="add*"propagation="REQUIRED"/> 
<tx:methodname="new*" propagation="REQUIRED" /> <tx:methodname="set*" propagation="REQUIRED"/> <tx:methodname="remove*"propagation="REQUIRED"/> 
<tx:methodname="delete*" propagation="REQUIRED"/> <tx:methodname="change*" propagation="REQUIRED"/> <tx:methodname="get*" propagation="REQUIRED"read-only="true"/> <tx:methodname="find*" propagation="REQUIRED" read-only="true"/> <tx:methodname="load*" propagation="REQUIRED" read-only="true"/> <tx:methodname="*" propagation="REQUIRED"read-only="true"/> 
</tx:attributes>

猜你喜欢

转载自blog.csdn.net/AthlenaA/article/details/82972056