spring基础总结

版权声明:本文为博主原创文章,转载标志原文地址。 https://blog.csdn.net/qq_38815856/article/details/82312679

目录

1. spring基本配置

1.1 导入jar包

1.2 创建配置信息

2. 注入实例

2.1 第一个项目构建

2.2 测试用例

2.3 流程概述

3. 其他注入法

3.1  其他方法注入

3.2 复杂类型注入

4. 使用注解注入

5. AOP开发

5.1 配置环境

5.2 执行流程

5.3 注解方式

6. 对数据库的操作

6.1 常规操作分析

6.2 利用spring操作数据库

7. 事务性操作

7.1 模拟转账

7.2 注解法配置


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步: 

  1. 从c3p0中获取连接池
  2. 加载连接必须的信息
  3. 新建JdbcTemplate类对象jt,它提供了数据库的操作方法
  4. 给jt设置要操作的数据源
  5. 设置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的基础知识就到这里

猜你喜欢

转载自blog.csdn.net/qq_38815856/article/details/82312679
今日推荐