目录
1. spring基本配置
1.1 导入jar包
新建web项目一,至少导入核心jar包,
- commons-logging-1.2.jar
- log4j-1.2.17.jar
- spring-aop-5.0.8.RELEASE.jar
- spring-beans-5.0.8.RELEASE.jar
- spring-context-5.0.8.RELEASE.jar
- spring-core-5.0.8.RELEASE.jar
- spring-expression-5.0.8.RELEASE.jar
- spring-test-5.0.8.RELEASE.jar
1.2 创建配置信息
在src下
新建log4j.properties可以为空内容
2. 注入实例
2.1 第一个项目构建
新建一个包cn.itcast_01_hello.pojo以及类
public class Car {
private String name;
private String color;
public Car() {
System.out.println("Car构造方法被调用");
}
//其他手动补全
public class Person {
private String name;
private String age;
private Car car;
public Person() {
super();
System.out.println("Person构造方法被调用");
}
//其他手动补全
在src下新建applicationContext_injectior.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd ">
<!-- 主要注入法:set方法,值注入 -->
<bean name="person1" class="cn.itcast_01_hello.pojo.Person">
<property name="name" value="Lucy"></property>
<property name="age" value="12"></property>
<!-- set方法,对象类型注入 -->
<property name="car" ref="car1"></property>
</bean>
<bean name="car1" class="cn.itcast_01_hello.Car">
<!-- set方法,值注入 -->
<property name="name" value="BUS"></property>
<property name="color" value="red"></property>
</bean>
</beans>
2.2 测试用例
@Test
public void testCreatePerson() {
AbstractApplicationContext context=new ClassPathXmlApplicationContext("applicationContext_injectior.xml");
//set注入
Person p1=(Person) context.getBean("person1");
System.out.println(p1);
}
2.3 流程概述
AbstractApplicationContext context=new ClassPathXmlApplicationContext("applicationContext_injectior.xml");
获取并解析xml的内容到对象context
Person p1=(Person) context.getBean("person1");
创建Person对象p1并获取xml中配置的<bean>,<bean>会映射对应的类并注入值
3. 其他注入法
3.1 其他方法注入
p注入需要引入约束规范(刚才已引入)
applicationContext_injectior.xml新增
<!-- 构造方法注入 -->
<bean name="person2" class="cn.itcast_01_hello.pojo.Person">
<constructor-arg name="name" value="Bob"></constructor-arg>
<constructor-arg name="age" value="15"></constructor-arg>
<constructor-arg name="car" ref="car1"></constructor-arg>
</bean>
<!-- p注入 ,要预先加入xmlns:p配置 -->
<bean name="person3" class="cn.itcast_01_hello.pojo.Person" p:name="Mike"
p:age="18" p:car-ref="car1" />
<!-- EL注入 -->
<bean name="person4" class="cn.itcast_01_hello.pojo.Person">
<property name="name" value="#{person1.name}"></property>
<property name="age" value="#{person1.age}"></property>
<property name="car" ref="car1" />
</bean>
测试用例:
@Test
public void testConstructor() {
AbstractApplicationContext context=new ClassPathXmlApplicationContext("applicationContext_injectior.xml");
//构造方法注入
Person p2=(Person) context.getBean("person2");
System.out.println(p2);
}
@Test
public void testP() {
AbstractApplicationContext context=new ClassPathXmlApplicationContext("applicationContext_injectior.xml");
//p注入
Person p3=(Person) context.getBean("person3");
System.out.println(p3);
}
@Test
public void testEL() {
AbstractApplicationContext context=new ClassPathXmlApplicationContext("applicationContext_injectior.xml");
//EL注入
Person p4=(Person) context.getBean("person4");
System.out.println(p4);
}
3.2 复杂类型注入
Person新增如下:
private String[] cars;
private List<String> list;
private Set<String> set;
private Map map;
private Properties properties;
xml新增如下
<bean name="person5" class="cn.itcast_01_hello.pojo.Person">
<property name="name" value="Wodeche"></property>
<property name="age" value="20"></property>
<property name="car" ref="car1" />
<!-- 数组注入 -->
<property name="cars">
<array>
<value>自行车</value>
<value>SUV</value>
<value>拖拉机</value>
</array>
</property>
<!-- list注入 -->
<property name="list">
<list>
<value>aaaa</value>
<value>bbbb</value>
<value>cccc</value>
</list>
</property>
<!-- set注入 -->
<property name="set">
<set>
<value>set4</value>
<value>set3</value>
<value>set1</value>
<value>set2</value>
</set>
</property>
<!-- map注入 -->
<property name="map">
<map>
<entry key="user" value="root"></entry>
<entry key="car" value-ref="car1"></entry>
<entry key-ref="car1" value="car"></entry>
<entry key-ref="car1" value-ref="car1"></entry>
</map>
</property>
<!-- properties注入 -->
<property name="properties">
<props>
<prop key="user">root</prop>
<prop key="pass">123</prop>
</props>
</property>
</bean>
测试用例:
@Test
public void testArrays() {
AbstractApplicationContext context=new ClassPathXmlApplicationContext("applicationContext_injectior.xml");
//复杂类型注入
Person p5=(Person) context.getBean("person5");
System.out.println(p5);
}
观察结果可以发现map集合只有三个值输出,因为最后两个的键值重复
4. 使用注解注入
构造项目二
新建一个cn.itcast_01_anno.pojo并新建类:
@Component("car")
public class Car {
private String name;
private String color;
//...
/**
* <bean name="person" class="cn.itcast_01_hello.pojo.Person"></bean>它相当于下面的注解
*/
@Component("person")
// 单例
@Scope(scopeName = "singleton")
//多例注解 @Scope(scopeName="prototype")
public class Person {
// 也可以写在setXxx上面注入
@Value("Bob")
private String name;
@Value("20")
private String age;
// 自动装配对象
// @Autowired
// 如果有两组数据,指明名字
// @Qualifier("car2")
// 还可以只写下面,一般采用这种
@Resource(name = "car2")
private Car car;
//...
在多个xml有不同的<bean>配置时,可以使用@Resource(name = "yourName") 指定配置
所以在这里要配置name = "car2",并且注解配置需要扫描,applicationContext.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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!--指定扫描某个包下的所有类中的注解,如果这个包下还有子包,子包也会被扫描 -->
<context:component-scan base-package="cn.itcast_01_anno.pojo"></context:component-scan>
<bean name="car1" class="cn.itcast_01_anno.pojo.Car">
<property name="name" value="SUV"></property>
<property name="color" value="blue"></property>
</bean>
<bean name="car2" class="cn.itcast_01_anno.pojo.Car">
<property name="name" value="UU"></property>
<property name="color" value="black"></property>
</bean>
</beans>
测试用例:
//使用了注解获取bean,需要让测试运行于Spring测试环境
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class RunWithTest {
//把一个bean注入到当前的对象
@Resource(name = "person")
private Person person;
@Test
public void test() {
System.out.println(person);
}
}
你也可以改变pojo类的注解@Resource(name = "car1")运行获得不同结果
5. AOP开发
5.1 配置环境
新建项目三
新增一下jar包
- aopalliance-.jar
- aspectj-weaver.jar
- spring-aspects-5.0.8.RELEASE.jar
创建cn.itcast_01_aop.advice及通知类:
//前置通知:在目标方法之前调用
//后置通知:(出现异常就不调用)在目标方法之后调用
//后置通知:(出现异常也会调用)在目标方法之后调用
//环绕通知:在目标方法之前,之后调用
//异常通知:出现异常调用
public class TransactionAdvace {
public void before() {
System.out.println("前置通知方法");
}
public void afterReturning() {
System.out.println("后置通知方法(出现异常就不调用)");
}
public void after() {
System.out.println("后置通知方法(不出现异常也会调用)");
}
public void afterException() {
System.out.println("异常被执行");
}
public Object around(ProceedingJoinPoint point) throws Throwable {
System.out.println("around前");
// 调用目标方法
Object proceed = point.proceed();
System.out.println("around后");
return proceed;
}
创建cn.itcast_01_aop.service及被通知的对象类:
public interface UserService{
public void save(String name);
public void delete();
public void update();
public void select();
}
它的接口类:
public class UserServiceImpl implements UserService {
@Override
public void save(String name) {
System.out.println("保存用户");
}
@Override
public void delete() {
System.out.println("删除用户");
}
@Override
public void update() {
System.out.println("更新用户");
}
@Override
public void select() {
System.out.println("选择用户");
}
}
配置applicationContext.xml将两者联系起来(xml需新增aop头文件约束):
<?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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<!-- 要通知的对象 -->
<bean name="TransactionAdvace" class="cn.itcast_01_aop.advice.TransactionAdvace" />
<!-- 目标对象(可删除) -->
<bean name="UserServiceImpl" class="cn.itcast_01_aop.service.UserServiceImpl" />
<!-- 将通知对象织入目标对象 -->
<aop:config>
<!-- 选择切入点 -->
<!-- 这是通常写法:* 表示匹配所有返回值, ..*匹配子包及任意字段名+ServiceImpl,.*(..)匹配所有方法和有无参数 -->
<aop:pointcut
expression="execution(* cn.itcast_01_aop.service..*ServiceImpl.*(..))"
id="pointcut" />
<aop:aspect ref="TransactionAdvace">
<aop:before method="before" pointcut-ref="pointcut" />
<aop:after-returning method="afterReturning"
pointcut-ref="pointcut" />
<aop:after method="after" pointcut-ref="pointcut" />
<aop:around method="around" pointcut-ref="pointcut" />
<aop:after-throwing method="afterException"
pointcut-ref="pointcut" />
</aop:aspect>
</aop:config>
</beans>
测试用例:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest {
@Resource(name = "UserServiceImpl")
private UserService UserService;
@Test
public void testUpdate() {
UserService.update();
}
}
5.2 执行流程
解析xml文件,这时实现织入过程,创建对象UserService获得xml的<bean>配置,然后执行方法
5.3 注解方式
在cn.itcast_01_aop.advice下新建类:
//作用是把当前类标识为一个切面供容器读取
@Aspect
//@aspect注释对于在类路径中自动检
//测是不够的:为了达到这个目的,您需要添加一个单独的@component注解
public class TransactionAdvaceAnno {
@Pointcut("execution(* cn.itcast_01_aop.service..*ServiceImpl.*(..))")
public void pointcut() {
}
@Before("TransactionAdvaceAnno.pointcut()")
public void before() {
System.out.println("前置通知方法");
}
@AfterReturning("TransactionAdvaceAnno.pointcut()")
public void afterReturning() {
System.out.println("后置通知方法(出现异常就不调用)");
}
@After("TransactionAdvaceAnno.pointcut()")
public void after() {
System.out.println("后置通知方法(不出现异常也会调用)");
}
@AfterThrowing("TransactionAdvaceAnno.pointcut()")
public void afterException() {
System.out.println("异常被执行");
}
@Around("TransactionAdvaceAnno.pointcut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
System.out.println("around前");
// 调用目标方法
Object proceed = point.proceed();
System.out.println("around后");
return proceed;
}
}
新建配置的applicationContextAnno.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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<!-- 目标对象 -->
<bean name="UserServiceImpl" class="cn.itcast_01_aop.service.UserServiceImpl" />
<!-- 通知对象 -->
<bean name="TransactionAdvaceAnno" class="cn.itcast_01_aop.advice.TransactionAdvaceAnno" />
<!-- 声明织入注解的方式 -->
<aop:aspectj-autoproxy />
</beans>
测试用例合并为如下:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:applicationContextAnno.xml", "classpath:applicationContext.xml" })
//@ContextConfiguration("classpath:applicationContextAnno.xml")
public class AopTest {
@Resource(name = "UserServiceImpl")
private UserService UserService;
@Test
public void testUpdate() {
UserService.update();
}
@Test
public void testSave() {
UserService.save("123");
}
}
6. 对数据库的操作
创建项目四,新增导入c3p0需要的jar包
最终的jar包如下:
- aopalliance-.jar
- aspectj-weaver.jar
- c3p0-0.9.5.2.jar
- commons-logging-1.2.jar
- log4j-1.2.17.jar
- mchange-commons-java-0.2.15.jar
- mysql-connector-java-8.0.11.jar
- spring-aop-5.0.8.RELEASE.jar
- spring-aspects-5.0.8.RELEASE.jar
- spring-beans-5.0.8.RELEASE.jar
- spring-context-5.0.8.RELEASE.jar
- spring-core-5.0.8.RELEASE.jar
- spring-expression-5.0.8.RELEASE.jar
- spring-jdbc-5.0.8.RELEASE.jar
- spring-test-5.0.8.RELEASE.jar
- spring-tx-5.0.8.RELEASE.jar
6.1 常规操作分析
数据库表:
CREATE DATABASE /*!32312 IF NOT EXISTS*/`spring` /*!40100 DEFAULT CHARACTER SET utf8 */;
USE `spring`;
/*Table structure for table `person` */
DROP TABLE IF EXISTS `person`;
CREATE TABLE `person` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`name` varchar(20) DEFAULT NULL,
`age` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=22 DEFAULT CHARSET=utf8;
/*Data for the table `person` */
insert into `person`(`id`,`name`,`age`) values (2,'Wang','47'),(3,'Nin','10'),(4,'Wang','21'),(10,'spr','16'),(11,'spr','16'),(12,'spr','16'),(13,'spr','18'),(14,'spr','18'),(15,'spr','20'),(16,'spr','20'),(17,'spr','20'),(18,'li','13'),(19,'spr','20'),(20,'li','13'),(21,'li','13');
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
@Test
public void testSave1() throws PropertyVetoException {
// 准备连接池
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setDriverClass("com.mysql.cj.jdbc.Driver");
dataSource.setJdbcUrl(
"jdbc:mysql://localhost:3306/spring?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false");
dataSource.setUser("root");
dataSource.setPassword("123");
JdbcTemplate jt=new JdbcTemplate();
jt.setDataSource(dataSource);
String sql = "insert into person (name,age) values(?,?)";
jt.update(sql, "li", "13");
}
所以分为一下5步:
- 从c3p0中获取连接池
- 加载连接必须的信息
- 新建JdbcTemplate类对象jt,它提供了数据库的操作方法
- 给jt设置要操作的数据源
- 设置sql语句进行操作
6.2 利用spring操作数据库
在src下创建连接语句db.properties:
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false
jdbc.username=root
jdbc.password=123
applicationContext.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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<!--指定扫描某个包下的所有类中的注解,如果这个包下还有子包,子包也会被扫描 -->
<context:component-scan base-package="cn.itcast_01_spring.dao"></context:component-scan>
<!--加载db.properties -->
<context:property-placeholder location="classpath:db.properties" />
<!-- 配置连接池 -->
<bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="user" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
</beans>
第一二步完成
创建cn.itcast_01_spring.pojo及实例类:
public class Person {
private int id;
private String name;
private String age;
//...
创建cn.itcast_01_spring.dao以及数据库的操作接口:
public interface PersonDao {
void save(Person person);
void delete(int id);
void update(Person person);
Person getById(int id);
List<Person> getAll();
int getTotalCount();
}
创建它的实现方法:
@Repository("personDao")
public class PersonDaoImpl implements PersonDao {
@Resource(name="jdbcTemplate")
private JdbcTemplate jt;
@Override
public void save(Person person) {
String sql = "insert into person (name,age) values(?,?)";
jt.update(sql, person.getName(), person.getAge());
}
@Override
public void delete(int id) {
String sql = "delete from person where id=?";
jt.update(sql, id);
}
@Override
public void update(Person person) {
String sql = "update person set name=?,age=? where id=?";
jt.update(sql, person.getName(), person.getAge(), person.getId());
}
@Override
public Person getById(int id) {
String sql = "select * from person where id=?";
Person person = jt.queryForObject(sql, new RowMapper<Person>() {
@Override
public Person mapRow(ResultSet rs, int index) throws SQLException {
return maoRowHandler(rs);
}
}, id);
return person;
}
@Override
public List<Person> getAll() {
String sql = "select * from person";
List<Person> list = jt.query(sql, new RowMapper<Person>() {
@Override
public Person mapRow(ResultSet rs, int index) throws SQLException {
return maoRowHandler(rs);
}
});
return list;
}
@Override
public int getTotalCount() {
String sql = "select count(1) from person";
int count = jt.queryForObject(sql, int.class);
return count;
}
private Person maoRowHandler(ResultSet rs) throws SQLException {
Person person = new Person();
person.setName(rs.getString("name"));
person.setAge(rs.getString("age"));
person.setId(rs.getInt("id"));
return person;
}
}
上面的代码实现了第五步的sql语句及其调用方法,注解部分意思就是(第四步):
<bean name="personDao" class="cn.itcast_01_spring.dao.PersonDaoImpl">
<!-- jdbcTemplate注入到PersonDaoImpl -->
<property name="jt" ref="jdbcTemplate"></property>
</bean>
所以自然xml中还要添加JdbcTemplate 的对象设置(第三步) :
<!-- JdbcTemplate -->
<bean name="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!-- 将上面的dataSource注入到JdbcTemplate -->
<property name="dataSource" ref="dataSource"></property>
</bean>
第三四五步完成
最后添加测试用例:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest {
@Resource(name = "personDao")
private PersonDao personDao;
@Test
public void testSave() {
Person person = new Person();
person.setName("spr");
person.setAge("20");
personDao.save(person);
System.out.println(person);
}
@Test
public void testDelete() {
personDao.delete(1);
}
@Test
public void testUpdate() {
Person person = new Person();
person.setName("Nin");
person.setAge("10");
person.setId(3);
personDao.update(person);
}
@Test
public void testGetId() {
Person person = personDao.getById(3);
System.out.println(person);
}
@Test
public void testGetAll() {
List<Person> person = personDao.getAll();
System.out.println(person);
}
@Test
public void testGetTotalCount() {
int count=personDao.getTotalCount();
System.out.println(count);
}
}
实际上还是更习惯于使用Mybatis操作
7. 事务性操作
数据库表:
/*
SQLyog Ultimate v12.09 (64 bit)
MySQL - 8.0.11
*********************************************************************
*/
/*!40101 SET NAMES utf8 */;
create table `account` (
`id` int (11),
`username` varchar (60),
`money` Decimal (12)
);
insert into `account` (`id`, `username`, `money`) values('1','Lucy','14555.55');
insert into `account` (`id`, `username`, `money`) values('2','Bob','20999.99');
7.1 模拟转账
创建项目五,模拟A向B转账
创建cn.itcast_01_spring.dao以及接口:
public interface AccountDao {
void addMoney(Integer id,Double money);
void subMoney(Integer id,Double money);
}
它的实现类:
@Repository("accountDao")
public class AccountDaoImpl implements AccountDao {
@Resource(name="jdbcTemplate")
private JdbcTemplate jt;
@Override
public void addMoney(Integer id, Double money) {
String sql="update account set money=money+? where id=?";
jt.update(sql,money,id);
}
@Override
public void subMoney(Integer id, Double money) {
String sql="update account set money=money-? where id=?";
jt.update(sql,money,id);
}
}
创建cn.itcast_01_spring.service及它的操作Dao层的接口:
public interface AccountService {
public void transfer(Integer from,Integer to,Double money);
}
它的实现类:
@Service("accountService")
public class AccountServiceImpl implements AccountService {
@Resource(name = "accountDao")
private AccountDao accountDao;
@Override
public void transfer(Integer from, Integer to, Double money) {
accountDao.subMoney(from, money);
//模拟异常
//int a=1/0;
accountDao.addMoney(to, money);
}
}
配置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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<!--指定扫描某个包下的所有类中的注解,如果这个包下还有子包,子包也会被扫描 -->
<context:component-scan base-package="cn.itcast_01_spring.dao"></context:component-scan>
<context:component-scan base-package="cn.itcast_01_spring.service"></context:component-scan>
<context:property-placeholder location="classpath:db.properties" />
<!-- 配置连接池 -->
<bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="user" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!-- JdbcTemplate -->
<bean name="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!-- 将上面的dataSource注入到JdbcTemplate -->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 事务管理器 -->
<bean name="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="transfer" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
<!-- 切面(织入) -->
<aop:config>
<!-- 切入点 (..*.*(..)))所有的子包和类,方法任意参数-->
<aop:pointcut expression="execution(* cn.itcast_01_spring.service..*.*(..))" id="txPointcut" />
<!-- 引用配置好的通知-->
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut" />
</aop:config>
</beans>
调用内置的事务通知以及配置切面,上面的代码后半部分内容类似通知方法:
将自定义的通知方法配置在<tx:advice>并织入service层的类,这样测试时service层的类就可以向执行通知方法一样执行我们配置的方法
测试用例:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class TxTest {
@Resource(name = "accountService")
private AccountService accountService;
@Test
public void testTransfer() {
accountService.transfer(1, 2, 1000D);
}
}
开启UserServiceImpl.java类的模拟异常,不会出现钱少了,但没转出去的情况
7.2 注解法配置
将上面的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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<!--指定扫描某个包下的所有类中的注解,如果这个包下还有子包,子包也会被扫描 -->
<context:component-scan base-package="cn.itcast_01_spring.dao"></context:component-scan>
<context:component-scan base-package="cn.itcast_01_spring.service"></context:component-scan>
<context:property-placeholder location="classpath:db.properties" />
<!-- 配置连接池 -->
<bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="user" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!-- JdbcTemplate -->
<bean name="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!-- 将上面的dataSource注入到JdbcTemplate -->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 事务管理器 -->
<bean name="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 配置数据源 -->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 开启注解事务管理 -->
<tx:annotation-driven/>
</beans>
新建一个AccountService实现类:
@Service("accountServiceAnno")
public class AccountServiceImplAnno implements AccountService{
@Resource(name = "accountDao")
private AccountDao accountDao;
@Override
// @Transactional(propagation=Propagation.REQUIRED) //控制事务传播。默认是Propagation.REQUIRED
// @Transactional(isolation=Isolation.DEFAULT) //控制事务隔离级别。默认跟数据库的默认隔离级别相同
// @Transactional(readOnly=false) //控制事务可读写还是只可读。默认可读写
// @Transactional(timeout=30) //控制事务的超时时间,单位秒。默认跟数据库的事务控制系统相同,又说是30秒
// @Transactional(rollbackFor=RuntimeException.class) //控制事务遇到哪些异常才会回滚。默认是RuntimeException
// @Transactional(rollbackForClassName=RuntimeException) //同上
// @Transactional(noRollbackFor=NullPointerException.class) //控制事务遇到哪些异常不会回滚。默认遇到非RuntimeException不会回滚
// @Transactional(noRollbackForClassName=NullPointerException)//同上
@Transactional(propagation=Propagation.REQUIRED,readOnly=false,isolation=Isolation.REPEATABLE_READ)
public void transfer(Integer from, Integer to, Double money) {
accountDao.subMoney(from, money);
//模拟异常
//int a=1/0;
accountDao.addMoney(to, money);
}
}
测试用例如下:
@Resource(name = "accountServiceAnno")
private AccountService accountServiceAnno;
@Test
public void testTransferAnno() {
accountServiceAnno.transfer(1, 2, 1000D);
}
运行结果与上面相同
至此spring的基础知识就到这里