标签:执行 llb string hash log xxx val 面向 user
在 SpringIOC 容器读取 Bean 配置创建 Bean 实例之前,必须对它进行实例化。只有在容器实例化后,才可以从 IOC 容器里获取 Bean 实例。
ApplicationContext 在初始化上下文时就实例化所有的单例
Spring支持3种依赖注入的方式
主程序:Main.java
public class Main { public static void main(String[] args) {//1. 创建 Spring 的 IOC 容器 ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); //2. 从 IOC 容器中获取 bean 的实例 HelloWorld helloWorld = (HelloWorld) ctx.getBean("helloWorld"); //根据类型来获取 bean 的实例: 要求在 IOC 容器中只有一个与之类型匹配的 bean, 若有多个则会抛出异常. //一般情况下, 该方法可用, 因为一般情况下, 在一个 IOC 容器中一个类型对应的 bean 也只有一个. //HelloWorld helloWorld1 = ctx.getBean(HelloWorld.class); //3. 使用 bean helloWorld.hello(); } }
JavaBean:HelloWorld.java
public class HelloWorld { private String user; public HelloWorld() { }
public HelloWorld(String user) {
this.user = user;
}
public void setUser(String user) { System.out.println("setUser:" + user); this.user = user; }public void hello(){ System.out.println("Hello: " + user); } }
配置文件:beas.xml
<!-- 配置一个 bean --> <bean id="helloWorld2" class="com.spring.helloworld.HelloWorld"> <!-- 为属性赋值 --> <!-- 通过属性注入: 通过 setter 方法注入属性值 --> <property name="user" value="Tom"></property> </bean>
JavaBean:Car.java
public class Car { private String company; private String brand; private int maxSpeed; private float price; public Car(String company, String brand, float price) { super(); this.company = company; this.brand = brand; this.price = price; } }
JavaBean:User.java(拥有Car类对象的集合)
public class User { private String userName;
private Car car; private List<Car> cars;
private Map<String, Car> cars2 private Properties properties;
public User() {
} ......
//一系列get和set方法 }
配置文件:bean.xml
<!-- 若一个 bean 有多个构造器,可以根据 index 和 type 进行更加精确的定位。 --> <bean id="car" class="com.spring.helloworld.Car"> <constructor-arg value="KUGA" index="1"></constructor-arg> <constructor-arg value="ChangAnFord" index="0"></constructor-arg> <!-- 或<constructor-arg index="0"><value>ChangAnFord</value> </constructor-arg> --> <!--若字面值中包含特殊字符, 则可以使用 CDATA 来进行赋值。 <constructor-arg index="0"> <value><![CDATA[<ChangAnFord>]]></value> </constructor-arg> --> <constructor-arg value="250000" type="float"></constructor-arg> </bean> <!-- 装配集合属性 --> <bean id="user" class="com.spring.helloworld.User"> <property name="userName" value="Jack"></property> <property name="car" ref="car"></property><!-- 引用外部bean。car即为上个bean的id --> <!-- 也可以写为 <property name="car"><ref bean="car" /></property> --> <!-- 也可以用内部 bean, 类似于匿名内部类对象. 不能被外部的 bean 来引用, 也没有必要设置 id 属性 <bean class="com.spring.helloworld.Car"> <constructor-arg value="KUGA" index="1"></constructor-arg> ... </bean> --> <!-- 为级联属性赋值,需定义setPrice方法(给car的price属性赋值) --> <property name="car.price" value="300"></property> <!-- 使用 list 元素来装配集合属性 --> <property name="cars"> <!-- 该list只能在此使用,若想在其他地方也能使用可以声明一个集合类型的bean --> <list> <ref bean="car" /> <ref bean="car2" /><!-- Car的其他对象,同上一个bean节点中的内容,这里没有写出 --> </list> </property> <!-- 声明集合类型的 bean,以供多个bean进行引用,需要导入util命名空间 <util:list id="carslist"> <ref bean="car"/> <ref bean="car2"/> </util:list> 引用外部声明的 list <property name="cars" ref="carslist"></property> --> <!-- 使用 map 元素来装配集合属性 --> <property name="cars2"> <map> <entry key="AA" value-ref="car"> <entry key="BB" value-ref="car2"> </map> </property> <!-- 配置Properties属性值 --> <property name="properties"> <prop key="user">root</prop> <prop key="password">123</prop> </property> </bean> <!-- 通过 p 命名空间为 bean 的属性赋值,需要先导入 p 命名空间。比传统配置简洁 --> <bean id="user2" class="com.spring.helloworld.User" p:cars-ref="cars" p:userName="Titannic" />
静态工厂类
public class StaticCarFactory{ private static Map<String, Car> cars = new HashMap<String, Car>(); static{ cars.put("audi", new Car("audi", 300000)); cars.put("ford", new Car("ford", 400000)); } public static Car getCar(String name){ return cars.get(name); } }
配置文件
<!-- class 属性:指向静态工厂方法的全类名 factory-method:指向静态工厂方法的名字 constructor-arg:如果工厂方法需要传入参数,则使用 constructor-arg 来配置参数 --> <bean id="car1" class="com.spring.beans.factory.StaticCarFactory" factory-method="getCar"> <constructor-arg value="audi"></constructor-arg> </bean>
工厂类
public class InstanceCarFactory{ private Map<String, Car> cars = null; public InstanceCarFactory(){ cars = new HashMap<String, Car>(); cars.put("audi", new Car("audi", 300000)); cars.put("ford", new Car("ford", 300000)); } public Car getCar(String brand){ return cars.get(brand); } }
配置文件
<!-- 配置工厂的实例 --> <bean id="carFactory" class="com.spring.beans.factory.InstanceCarFactory"></bean> <!-- 通过实例工厂方法来配置 Bean -->
<!-- factory-bean:指向实例工厂方法的 Bean factory-method:指向静态工厂方法的名字 constructor-arg:如果工厂方法需要传入参数,则使用 constructor-arg 来配置参数 --> <bean id="car2" factory-bean="carFactory" factory-method="getCar"> <constructor-arg value="ford"></constructor-arg> </bean>
工厂类
public class CarFactoryBean implements FactoryBean<Car>{ private String brand; public void setBrand(String brand){ this.brand = brand; } @Override public Car getObject() throws Exception{ return new Car(brand,500000); } @Override public Class<?> getObjectType(){ return Car.class; } @Override puiblic boolean isSingleton(){ return true; } }
配置文件
<!-- 通过 FactoryBean 来配置 Bean 的实例 class:指向 FactoryBean 的全类名 property:配置 FactoryBean 的属性 返回 Car 的实例 --> <bean id="car" class="com.spring.beans.factory.CarFactoryBean"> <property name="brand" value="BMW"></property> </bean>
组件扫描:Spring 能够从 classpath 下自动扫描,侦测和实例化具有特定注解的组件,并自动为其命名为:首字母小写的类名。
组件:
@Component:基本注解,标识了一个受 Spring 管理的组件
@Respository:标识持久层组件
@Service:标识服务层(业务层)组件
@Controller:标识表现层组件
main.java
ApplicationContext ctx = new new ClassPathXmlApplicationContext("bean-annotation"); UserController userController = (UserController)ctx.getBean("userController"); UserRepository userRepository = (UserRepository)ctx.getBean("userRepository");
相关类
@Autowired 自动装配:在IOC容器中寻找与该类型兼容的 Bean。 @Autowired(required=false) //即使该类不在IOC中也可以被装配
@Qualifier("xxx"):指定装配xxx
//这种情况自动命名为 testObject @Component public class TestObject{ //... } @Controller public class UserController{ @Autowired
private UserService userService;
//... } @Service public class UserService{ @Autowired
@Qualifier("userRepositoryImpl")
private UserRepository userRepository;
//... } public interface UserRepository{ void save(); } //手动命名 @Repository("userRepository") public class UserRepositoryImpl{ @Override public void save(){ //... } }
配置文件
<!-- 配置自动扫描的包: 需要导入 context 命名空间。 Spring会扫描该包和其子包下具有特定注解的组件。 --> <!-- 1. 可以通过 resource-pattern 指定扫描的资源。 --> <context:component-scan base-package="com.spring.annotation" resource-pattern="*.class"> </context:component-scan> <!-- 2. context:exclude-filter 子节点指定排除哪些表达式的组件。 --> <context:component-scan base-package="com.spring.annotation"> <!-- 排除指定组件 --> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"> <!-- 排除指定类 --> <context:exclude-filter type="assignable" expression="com.spring.beans.annotation.UserRepository"> </context:component-scan> <!-- 3. context:include-filter 子节点指定包含哪些表达式的组件,该子节点需要 use-default-filters="false" 配合使用。 use-default-filters="false" 不使用默认的过滤器。 --> <context:component-scan base-package="com.spring.annotation" use-default-filters="false"> <!-- 只包含指定组件 --> <context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"> <!-- 只包含指定类 --> <context:include-filter type="assignable" expression="com.spring.beans.annotation.UserRepositoryrg"> </context:component-scan>
方式:在<bean>的autowire属性里指定自动装配的模式
分类:
使用:
<bean id="person" class="com.spring.autowire.Person" p:name="Tom"
autowire="byName" />
<bean id="address" class="com.spring.beans.Address" p:city="AAA" p:street="BBB" /> <bean id="address2" p:street="CCC" parent="address" />
<bean id="car" class="com.spring.beans.Car" p:brand="Audi" p:price="300000" /> <bean id="person" class="com.spring.beans.Person" p:name="Tom" depends-on="car" />
使用 scope 属性设置作用域,默认为 singleton(单例)。
种类:
<bean id="car" class="com.spring.beans.Car" scope="prototype" p:brand="Audi" p:price="300000" />
需求:实际项目开发中,要是想对某一 Bean 的属性进行修改时我们在其配置文件中找到对应的 Bean 才能为其属性赋值。要是项目中有过多的 Bean ,查找起来就越困难。这时我们可以使用外部属性文件让这些部署细节与 Bean 配置相分离。
准备:导入context命名空间
配置文件
<context:property-placeholder location="classpath:db.properties" /> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <!-- 使用外部化属性文件的属性 --> <property name="user" value="${user}"></property> <property name="password" value="${password}"></property> <property name="driverClass" value="${driverClass}"></property> <property name="jdbcurl" value="${jdbcurl}"></property> </bean>
db.properties
jdbc.user=root jdbc.password=1230 jdbc.driverClass=com.mysql.jdbc.Driver jdbc.jdbcUrl=jdbc:mysql:///test
SpringIOC 容器可以管理 Bean 的生命周期。
使用:在 Bean 的声明里设置 init-method 和 destroy-method 属性,为 Bean 指定初始化和销毁方法。
生命周期管理过程:
<!-- Car类中定义了 myInit() 和 myDestroy() 方法 --> <bean id="car" class="com.spring.beans.Car" init-method="myInit" destroy-method="myDestroy"> <property name="brand" value="Audi"></property> </bean>
作用:在调用每个 Bean 的初始化方法前后处理程序。
注意:需实现 BeanPostProcessor 接口。
添加后置处理器后的生命周期管理过程:
MyBeanPostProcessor.java
public class MyBeanPostProcessor implements BeanPostProcessor{ @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException{ System.out.println("postProcessBeforeInitialization"); if("car".equals(beanName)){ //.... } return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException{ System.out.println("postProcessAfterInitialization"); return bean; } }
配置文件
<!-- 配置 Bean 的后置处理器:不需要 id,IOC 容器自动识别是一个 BeanPostProcessor -->
<bean class="com.spring.beans.MyBeanPostProcessor"></bean>
简介:AOP(Aspect-Oriented Programming,面向切面编程),是对OOP的补充。主要变成对象是切面。一个方法中有很多步骤,可以把每个方法中统一存在的步骤看成一个切面。比如像每个方法被调用时需记录日志的这一步骤可以被看成一个切面,而AOP就是在不改变源码的情况下使关注点转向这些切面。
作用:可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能。
术语:
需要 jar 包:
通知注解:
切面类
//通过添加 @Aspect 注解声明一个 bean 是一个切面 @Aspect
//注:目标方法所在的类也需要加上 @Component 注解 @Component public class LoggingAspect { /** * 定义一个方法,用于声明切入点表达式。 一般地, 该方法中再不需要添入其他的代码。 * 使用 @Pointcut 来声明切入点表达式。 * 后面的其他通知直接使用方法名来引用当前的切入点表达式。 */ @Pointcut("execution(public int com.atguigu.spring.aop.ArithmeticCalculator.*(..))") public void declareJointPointExpression(){} //声明该方法是一个前置通知:在目标方法开始之前执行 @Before("execution(public int com.spring.aop.ArithmeticCalculator.*(int, int))") public void beforeMethod(JoinPoint joinPoint){ String methodName = joinPoint.getSignature().getName(); Object [] args = joinPoint.getArgs(); System.out.println("The method " + methodName + " begins with " + Arrays.asList(args)); } //声明该方法是一个后置通知:在目标方法执行之后(无论是否发生异常)执行。在后置通知中还不能访问目标方法执行的结果 @After("execution(* com.spring.aop.*.*(..))") //被通知的对象(目标)为 com.spring.aop 下的所有方法 public void afterMethod(JoinPoint joinPoint){ String methodName = joinPoint.getSignature().getName(); System.out.println("The method " + methodName + " ends"); } /** * 在方法法正常结束受执行的代码 * 返回通知是可以访问到方法的返回值的!
*
* 使用了切点表达式,等同于 value="execution(public int com.atguigu.spring.aop.ArithmeticCalculator.*(..))" */ @AfterReturning(value="declareJointPointExpression()", returning="result") public void afterReturning(JoinPoint joinPoint, Object result){ String methodName = joinPoint.getSignature().getName(); System.out.println("The method " + methodName + " ends with " + result); } /** * 在目标方法出现异常时会执行的代码。 * 可以访问到异常对象;且可以指定在出现特定异常时在执行通知代码。 */ @AfterThrowing(value="declareJointPointExpression()", throwing="e") public void afterThrowing(JoinPoint joinPoint, Exception e){ String methodName = joinPoint.getSignature().getName(); System.out.println("The method " + methodName + " occurs excetion:" + e); }
/** * 环绕通知需要携带 ProceedingJoinPoint 类型的参数。 * 环绕通知类似于动态代理的全过程:ProceedingJoinPoint 类型的参数可以决定是否执行目标方法。 * 且环绕通知必须有返回值, 返回值即为目标方法的返回值 */ @Around("execution(public int com.atguigu.spring.aop.ArithmeticCalculator.*(..))") public Object aroundMethod(ProceedingJoinPoint pjd){ Object result = null; String methodName = pjd.getSignature().getName(); try { //前置通知 System.out.println("The method " + methodName + " begins with " + Arrays.asList(pjd.getArgs())); //执行目标方法 result = pjd.proceed(); //返回通知 System.out.println("The method " + methodName + " ends with " + result); } catch (Throwable e) { //异常通知 System.out.println("The method " + methodName + " occurs exception:" + e); throw new RuntimeException(e); } //后置通知 System.out.println("The method " + methodName + " ends"); return result; } }
applicationContext.xml
<!-- 自动扫描的包 --> <context:component-scan base-package="com.atguigu.spring.aop"></context:component-scan> <!-- 使 AspectJ 的注解起作用:自动为匹配的类生成代理对象 --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
可以用 @Order(num) 来指定切面的优先级,且值越小优先级越高
@Order(1) @Aspect @Component public class VlidationAspect { @Before("com.spring.aop.LoggingAspect.declareJointPointExpression()") public void validateArgs(JoinPoint joinPoint){ System.out.println("-->validate:" + Arrays.asList(joinPoint.getArgs())); } }
每个 aop:aspect 节点为一个切面
<!-- 配置 目标 bean -->
<bean id="arithmeticCalculator" class="com.atguigu.spring.aop.xml.ArithmeticCalculatorImpl"></bean>
<!-- 配置切面的 bean. -->
<bean id="loggingAspect" class="com.atguigu.spring.aop.xml.LoggingAspect"></bean>
<bean id="vlidationAspect" class="com.atguigu.spring.aop.xml.VlidationAspect"></bean>
<!-- 配置 AOP -->
<aop:config>
<!-- 配置切点表达式 -->
<aop:pointcut expression="execution(* com.atguigu.spring.aop.xml.ArithmeticCalculator.*(int, int))" id="pointcut"/>
<!-- 配置切面及通知 -->
<aop:aspect ref="loggingAspect" order="2">
<aop:before method="beforeMethod" pointcut-ref="pointcut"/>
<aop:after method="afterMethod" pointcut-ref="pointcut"/>
<aop:after-throwing method="afterThrowing" pointcut-ref="pointcut" throwing="e"/>
<aop:after-returning method="afterReturning" pointcut-ref="pointcut" returning="result"/>
<!--
<aop:around method="aroundMethod" pointcut-ref="pointcut"/>
-->
</aop:aspect>
<aop:aspect ref="vlidationAspect" order="1">
<aop:before method="validateArgs" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
Spring 提供了 JdbcTemplate 类。
方法签名:
public class JDBCTest { private ApplicationContext ctx = null; private JdbcTemplate jdbcTemplate; private NamedParameterJdbcTemplate namedParameterJdbcTemplate; { ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); jdbcTemplate = (JdbcTemplate) ctx.getBean("jdbcTemplate"); namedParameterJdbcTemplate = ctx.getBean(NamedParameterJdbcTemplate.class); } /** * 1. 执行 INSERT, UPDATE, DELETE */ @Test public void testUpdate(){ String sql = "UPDATE employees SET last_name = ? WHERE id = ?"; jdbcTemplate.update(sql, "Jack", 5); } /** * 2. 执行批量更新: 批量的 INSERT, UPDATE, DELETE * 最后一个参数是 Object[] 的 List 类型: 因为修改一条记录需要一个 Object 的数组 */ @Test public void testBatchUpdate(){ String sql = "INSERT INTO employees(last_name, email, dept_id) VALUES(?,?,?)"; List<Object[]> batchArgs = new ArrayList<>(); batchArgs.add(new Object[]{"AA", "aa@atguigu.com", 1}); batchArgs.add(new Object[]{"BB", "bb@atguigu.com", 2}); batchArgs.add(new Object[]{"CC", "cc@atguigu.com", 3}); batchArgs.add(new Object[]{"DD", "dd@atguigu.com", 3}); batchArgs.add(new Object[]{"EE", "ee@atguigu.com", 2}); jdbcTemplate.batchUpdate(sql, batchArgs); } /** * 3. 从数据库中获取一条记录, 实际得到对应的一个对象 * 1)RowMapper:指定如何去映射结果集的行, 常用的实现类为 BeanPropertyRowMapper * 2)使用 SQL 中列的别名完成列名和类的属性名的映射. 例如 last_name lastName * 3)不支持级联属性. JdbcTemplate 只是一个 JDBC 的小工具, 而不是 ORM 框架 */ @Test public void testQueryForObject(){ String sql = "SELECT id, last_name lastName, email FROM employees WHERE id = ?"; RowMapper<Employee> rowMapper = new BeanPropertyRowMapper<>(Employee.class); Employee employee = jdbcTemplate.queryForObject(sql, rowMapper, 1); } /** * 4. 查到实体类的集合 * 注意调用的不是 queryForList 方法 */ @Test public void testQueryForList(){ String sql = "SELECT id, last_name lastName, email FROM employees WHERE id > ?"; RowMapper<Employee> rowMapper = new BeanPropertyRowMapper<>(Employee.class); List<Employee> employees = jdbcTemplate.query(sql, rowMapper,5); } /** * 5. 获取单个列的值, 或做统计查询 */ @Test public void testQueryForObject2(){ String sql = "SELECT count(id) FROM employees"; long count = jdbcTemplate.queryForObject(sql, Long.class); System.out.println(count); } /** * 6. 更新(可以为参数起名字). * 若有多个参数, 则不用再去对应位置, 直接对应参数名, 便于维护 */ @Test public void testNamedParameterJdbcTemplate(){ String sql = "INSERT INTO employees(last_name, email, dept_id) VALUES(:ln,:email,:deptid)"; Map<String, Object> paramMap = new HashMap<>(); paramMap.put("ln", "FF"); paramMap.put("email", "ff@atguigu.com"); paramMap.put("deptid", 2); namedParameterJdbcTemplate.update(sql, paramMap); } /** * 7. 使用具名参数时, 可以使用 update(String sql, SqlParameterSource paramSource) 方法进行更新操作 * 1)SQL 语句中的参数名和类的属性一致! * 2)使用 SqlParameterSource 的 BeanPropertySqlParameterSource 实现类作为参数 */ @Test public void testNamedParameterJdbcTemplate2(){ String sql = "INSERT INTO employees(last_name, email, dept_id) VALUES(:lastName,:email,:deptId)"; Employee employee = new Employee(); employee.setLastName("XYZ"); employee.setEmail("xyz@sina.com"); employee.setDeptId(3); SqlParameterSource paramSource = new BeanPropertySqlParameterSource(employee); namedParameterJdbcTemplate.update(sql, paramSource); } }
applicationContext.xml
<!-- 导入资源文件 --> <context:property-placeholder location="classpath:db.properties"/> <!-- 配置 C3P0 数据源 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="user" value="${jdbc.user}"></property> <property name="password" value="${jdbc.password}"></property> <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property> <property name="driverClass" value="${jdbc.driverClass}"></property> <property name="initialPoolSize" value="${jdbc.initPoolSize}"></property> <property name="maxPoolSize" value="${jdbc.maxPoolSize}"></property> </bean> <!-- 配置 Spirng 的 JdbcTemplate --> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 配置 NamedParameterJdbcTemplate, 该对象可以使用具名参数, 其没有无参数的构造器, 所以必须为其构造器指定参数 --> <bean id="namedParameterJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate"> <constructor-arg ref="dataSource"></constructor-arg> </bean>
db.properties
jdbc.user=root jdbc.password=1230 jdbc.driverClass=com.mysql.jdbc.Driver jdbc.jdbcUrl=jdbc:mysql:///spring jdbc.initPoolSize=5 jdbc.maxPoolSize=10
编程式事务管理:将事务管理代码嵌入到业务方法中来控制事务的提交和回滚。
声明式事务管理:将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。
事务传播属性:当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。
传播行为:
@Autowired private BookShopDao bookShopDao; //添加事务注解 //1.使用 propagation 指定事务的传播行为。//2.使用 isolation 指定事务的隔离级别, 最常用的取值为 READ_COMMITTED。 //3.默认情况下 Spring 的声明式事务对所有的运行时异常进行回滚. 也可以通过对应的属性进行设置. 通常情况下去默认值即可。 //4.使用 readOnly 指定事务是否为只读. 表示这个事务只读取数据但不更新数据。
//5.使用 timeout 指定强制回滚之前事务可以占用的时间。若超过此时间则强制回滚。 @Transactional(propagation=Propagation.REQUIRES_NEW, isolation=Isolation.READ_COMMITTED,
noRollbackFor={UserAccountException.class},//对 UserAccount 异常不进行回滚 readOnly=false, timeout=3) @Override public void purchase(String username, String isbn) { try { Thread.sleep(5000); } catch (InterruptedException e) {} //1. 获取书的单价 int price = bookShopDao.findBookPriceByIsbn(isbn); //2. 更新数的库存 bookShopDao.updateBookStock(isbn); //3. 更新用户余额 bookShopDao.updateUserAccount(username, price); }
applicationContext-tx.xml
<!-- 配置事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 启用事务注解 需导入 tx 命名空间 --> <tx:annotation-driven transaction-manager="transactionManager"/>
2)使用Xml的方式声明事务
applicationComtext-tx-xml.xml
<!-- 1. 配置事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 2. 配置事务属性 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <!-- 根据方法名指定事务的属性 --> <tx:method name="purchase" propagation="REQUIRES_NEW"/> <tx:method name="get*" read-only="true"/> <tx:method name="find*" read-only="true"/> <tx:method name="*"/> </tx:attributes> </tx:advice> <!-- 3. 配置事务切入点, 以及把事务切入点和事务属性关联起来 --> <aop:config>
<!-- 作用于哪些方法上 --> <aop:pointcut expression="execution(* com.spring.tx.xml.service.*.*(..))" id="txPointCut"/>
<!-- 把切入点和属性相关联 --> <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/> </aop:config>
标签:执行 llb string hash log xxx val 面向 user
原文地址:http://www.cnblogs.com/CComma/p/7224554.html