自学spring的回顾(3/3)
spring事务
处理事务怎么做
1、事务内部提交:告诉spring使用哪种数据库访问事务类型
2、什么样的事务:
(1)事务的隔离级别:有4个隔离级别:
READ_UNCOMMITTED:读未提交
READ_COMMITTED:读已提交
REPEATABLE_READ:可重复读。默认
SERIALIZABLE:串行化
(2)事务的超时时间:默认-1
(3)事务的传播行为:常用的有3个
PROPAGATION_REQUIRED:指定的方法必须在事务内执行
若没有事务,则创建一个新事务。默认
PROPAGATION_REQUIRES_NEW:总是新建一个事务,若存在当前事务,
就将当前事务挂起,直到新事务执行完毕。
PROPAGATION_SUPPORTS:支持当前事务,若没有事务,也可以以非事务进行处理
3、spring提交事务或回滚的时机:
当你业务方法,执行成功,没有异常抛出,当方法执行完毕,提交
当你业务方法抛出异常,spring回滚
当你业务方法抛出非运行时异常,提交事务
spring整合mybatis(ioc和aop处理事务的运用)
实现商品购买和商品成交记录(遇到商品号不对或者商品数量不足会自动回滚)
2个数据库的表:
CREATE TABLE `goods` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`amount` int(11) NOT NULL,
PRIMARY KEY (`id`)
)
CREATE TABLE `sale` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`goodid` int(11) NOT NULL,
`num` int(11) NOT NULL,
PRIMARY KEY (`id`)
)
1、创建maven项目
2、加入依赖
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.9</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.12</version>
</dependency>
3、创建实体类
根据数据库表自行创建。
4、创建Dao和Mapper
public interface GoodDao {
int update(Goods goods);
goods select(Integer num);
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.my.dao.GoodDao">
<update id="update" >
update goods set amount=amount-#{amount} where id=#{id}
</update>
<select id="select" resultType="com.my.shiticlass.goods">
select * from goods where id=#{num}
</select>
</mapper>
public interface SaleDao {
int insert(Sale sale);
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.my.dao.SaleDao">
<insert id="insert">
insert into sale(goodid,num) values (#{goodid},#{num})
</insert>
</mapper>
5、创建mybatis主配置
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting value="STDOUT_LOGGING" name="logImpl"/><!--输出日志信息-->
</settings>
<typeAliases>
<package name="com.my.shiticlass"/><!--实体类所在的包-->
</typeAliases>
<mappers>
<package name="com.my.dao"/><!--Dao和mapper所在的包-->
</mappers>
</configuration>
6、创建异常类继承RuntimeException
public class NotEnough extends RuntimeException {//由于spring中事务回滚通常是处理运行时异常
public NotEnough() {
super();
}
public NotEnough(String message) {
super(message);
}
}
7、创建service业务逻辑代码
public interface Ser {
void my(Integer goodsnum, Integer salenum);
}
public class Service implements Ser{
private SaleDao saleDao;
private GoodDao goodDao;
public SaleDao getSaleDao() {
return saleDao;
}
public void setSaleDao(SaleDao saleDao) {
this.saleDao = saleDao;
}
public GoodDao getGoodDao() {
return goodDao;
}
public void setGoodDao(GoodDao goodDao) {
this.goodDao = goodDao;
}
public Service(SaleDao saleDao, GoodDao goodDao) {
this.saleDao = saleDao;
this.goodDao = goodDao;
}
@Override
@Transactional//事务注解的添加,可以根据业务要求的不同,对属性进行修改,这里使用默认的属性值
//这里没有aop动态代理的切面方法,是因为spring已经在事务中写好了切面。
public void my(Integer goodid, Integer num) {
Sale sale=new sale();
sale.setGoodid(goodid);
sale.setNum(num);
saleDao.insert(sale);
Goods select = goodDao.select(goodid);
if(select==null||num>select.getAmount()){
throw new Notenough("输入的商品编号不正确或者商品数量不足");
}
Goods goods1=new goods();
goods1.setId(goodid);
goods1.setAmount(num);
goodDao.update(goods1);
}
}
8、创建spring配置文件
<?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:util="http://www.springframework.org/schema/util"
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/util
https://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<bean id="DataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init"
destroy-method="close"><!--这里使用druid连接数据库,作为数据源-->
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="maxActive" value="20"></property>
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><!--创建sqlSession工厂对象,它需要数据源和mybatis配置文件的地址-->
<property name="dataSource" ref="DataSource"></property>
<property name="configLocation" value="classpath:mybatis-config.xml"></property>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"><!--多个动态代理对象的创建,这里不使用id是因为获取动态代理对象不方便,首字母小写-->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
<property name="basePackage" value="com.my.dao"></property>
</bean>
<bean id="service" class="com.my.service.Service"><!--业务逻辑类的对象-->
<property name="GoodDao" ref="goodDao"></property>
<property name="saleDao" ref="saleDao"></property>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><!--事务管理器,只需要数据源-->
<property name="dataSource" ref="DataSource"></property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/><!--事务驱动,驱动事务管理器-->
</beans>
9、写测试方法
public class MyTest {
@Test
public void test01(){
String config="ApplicationContext.xml";
ApplicationContext applicationContext=new ClassPathXmlApplicationContext(config);
Ser service1 = (Ser) applicationContext.getBean("service");
service1.my(1,100);
}
}
注:如果配置多个方法的事务属性,可以采用、
<tx:advice transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="method1" isolation="" propagation="" read-only="" rollback-for="" timeout=""/>
<tx:method name="method2" isolation="" propagation="" read-only="" rollback-for="" timeout=""/>
</tx:attributes>
</tx:advice>
spring中web的容器创建
由于web中每次刷新请求或者提交数据都需要创建一次容器,效率会非常低,可以将容器放入到全局作用域中(ServletContext),多次请求都会使用这一个容器。(使用监听器处理这些)
1、首先加入依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
2、在web.xml配置文件中写入listener标签
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
3、由于监听器要创建全局作用域对象,就要加载WEB-INF下面的applicationContext.xml文件,是默认路径,所以要求修改默认路径
<context-param>
<para-name>contextConfigLocation</para-name>
<para-value>classpath:</para-value>
</context-param>
4、然后就可以在Servlet类中去使用监听器创建的容器:
WebApplicationContext ctx=null;//这里的容器是在web中使用的容器
ctx=WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());