五. 声明式事务
- 编程式事务:
1.1 由程序员编程事务控制代码.
1.2 OpenSessionInView 编程式事务 - 声明式事务:
先引入依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.9.RELEASE</version>
</dependency>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:cache="http://www.springframework.org/schema/cache"
xsi:schemaLocation="
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd
http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache-3.1.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<context:component-scan base-package="com.xmm.dao" />
<context:component-scan base-package="com.xmm.service.impl" />
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl"
value="jdbc:mysql://localhost:3306/test?serverTimezone=UTC"></property>
<property name="user" value="root"></property>
<property name="password" value="root"></property>
</bean>
<!--spring管理session工厂 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:mybatis.xml" /> <!--记住在mapper.xml中执行sql语句 -->
</bean>
<!-- ========scan for mappers and let them be autowired ======== -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 注入sqlSessionFactory -->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
<!-- 给出需要扫描Dao接口包 -->
<property name="basePackage" value="com.xmm.dao" />
</bean>
<!-- -->
<!-- ====事务管理器=== -->
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置声明式事务 -->
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<!-- 哪些方法需要有事务控制 -->
<!-- 方法以 ins 开头事务管理 -->
<tx:method name="transferSalary" />
<tx:method name="transferTo" />
</tx:attributes>
</tx:advice>
<aop:config>
<!-- 切点范围设置大一些 -->
<aop:pointcut expression="execution(* com.xmm.service.impl.*.*(..))"
id="mypoint" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="mypoint" />
</aop:config>
<!--不添加下方标签报:Bean named 'employeeServiceImpl' is expected to be of type 'com.xmm.service.impl.EmployeeServiceImpl' but was actually of type 'com.sun.proxy.$Proxy27' -->
<aop:aspectj-autoproxy proxy-target-class="true"/>
<!--开启aspectj代理,并暴露aop代理到ThreadLocal-->
<aop:aspectj-autoproxy expose-proxy="true"/>
<!-- 使得事务注解生效 -->
<tx:annotation-driven transaction-manager="txManager"/>
</beans>
下面为详解
2.1 事务控制代码已经由 spring 写好.程序员只需要声明出哪些方法需要进行事务控制和如何进行事务控制.
4. 声明式事务都是针对于 ServiceImpl 类下方法的.
4. 事务管理器基于通知(advice)的.
5. 在 spring 配置文件中配置声明式事务
<context:property-placeholder location="classpath:db.properties,classpath:second.properties"/>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!-- spring-jdbc.jar 中 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置声明式事务 -->
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<!-- 哪些方法需要有事务控制 -->
<!-- 方法以 ins 开头事务管理 -->
<tx:method name="ins*" />
<tx:method name="del*" />
<tx:method name="upd*" />
<tx:method name="*" />
<!-- tx:method中的属性有
name: 事务作用在的方法名
isolation:DEFAULT ,事务的隔离级别。
propagation:事务的传播行为.
read-only:false,不是只读
timeout:-1
no-rollback-for:发生哪些异常不回滚
rollback-for:发生哪些异常回滚事务
-->
</tx:attributes>
</tx:advice>
<aop:config>
<!-- 切点范围设置大一些 (注意(* com.bjsxt.service.impl.*.*(..))中*和com之间有一个空格)-->
<aop:pointcut expression="execution(* com.bjsxt.service.impl.*.*(..))" id="mypoint" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="mypoint" />
</aop:config>
可能会报:错误1.Bean named ‘employeeServiceImpl’ is expected to be of type ‘com.xmm.service.impl.EmployeeServiceImpl’ but was actually of type ‘com.sun.proxy.$Proxy27’ 。
错误2.注解无效
这个错误的原因是spring aop代理混用的问题
https://blog.csdn.net/jiadajing267/article/details/81056057
解决方法:添加<aop:aspectj-autoproxy proxy-target-class="true"/>
<!-- ====事务管理器=== -->
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置声明式事务 -->
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<!-- isolation:DEFAULT ,事务的隔离级别。
propagation:事务的传播行为.
read-only:false,不是只读
timeout:-1
no-rollback-for:发生哪些异常不回滚
rollback-for:发生哪些异常回滚事务
method name:事务作用在什么方法上-->
<tx:method name="ins*" />
<tx:method name="del*" />
<tx:method name="upd*" />
<tx:method name="*" />
</tx:attributes>
</tx:advice>
<aop:config>
<!-- 切点范围设置大一些 -->
<aop:pointcut expression="execution(* com.xmm.service.impl.*.*(..))"
id="mypoint" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="mypoint" />
</aop:config>
<!--不添加下方标签报:Bean named 'employeeServiceImpl' is expected to be of type 'com.xmm.service.impl.EmployeeServiceImpl' but was actually of type 'com.sun.proxy.$Proxy27' -->
<aop:aspectj-autoproxy proxy-target-class="true"/>
<!--开启aspectj代理,并暴露aop代理到ThreadLocal-->
<aop:aspectj-autoproxy expose-proxy="true"/>
<!-- 使得事务注解生效 -->
<tx:annotation-driven transaction-manager="txManager"/>
6.再在类或方法上使用@Transactional注解,如
@Transactional
public void transferSalary(String from, String to, float salary) {
employeeMapper.transferFrom(from, salary);
//模拟异常
int i=0;
if(i==0) {
throw new RuntimeException("转账出错啦!!!");
}
employeeMapper.transferTo(to, salary);
}
测试事务的传播
@Transactional
public void transferSalary(String from, String to, float salary) {
employeeMapper.transferFrom(from, salary);
//模拟异常
int i=1;
if(i==0) {
throw new RuntimeException("转账出错啦!!!");
}
//employeeMapper.transferTo(to, salary);
((EmployeeServiceImpl) AopContext.currentProxy()).transferTo(to,salary);//这种方式事务传播有效
//transferTo(to,salary); //这种方式事务传播无效
}
@Transactional(propagation=Propagation.REQUIRED)
public void transferTo(String to,float salary) {
employeeMapper.transferTo(to, salary);
}
声明式事务中属性解释
- name=”” 哪些方法需要有事务控制
1.1 支持*通配符 - readonly=”boolean” 是否是只读事务.
2.1 如果为 true,告诉数据库此事务为只读事务.数据化优化,会对性能有一定提升,所以只要是查询的方法,建议使用此数据.
2.2 如果为 false(默认值),事务需要提交的事务.建议新增,删除,修
改. - propagation 控制事务传播行为.
3.1 当一个具有事务控制的方法被另一个有事务控制的方法调用后,需要如何管理事务(新建事务?在事务中执行?把事务挂起?报异常?)
3.2 REQUIRED (默认值): 如果当前有事务,就在事务中执行,如果当前没有事务,新建一个事务.
3.3 SUPPORTS:如果当前有事务就在事务中执行,如果当前没有事务,就在非事务状态下执行.
3.4 MANDATORY:必须在事务内部执行,如果当前有事务,就在事务中执行,如果没有事务,报错.
3.5 REQUIRES_NEW:必须在事务中执行,如果当前没有事务,新建事务,如果当前有事务,把当前事务挂起.
3.6 NOT_SUPPORTED:必须在非事务下执行,如果当前没有事务,正常执行,如果当前有事务,把当前事务挂起.
3.7 NEVER:必须在非事务状态下执行,如果当前没有事务,正常执行, 如果当前有事务,报错.
3.8 NESTED:必须在事务状态下执行.如果没有事务,新建事务,如果当前有事务,创建一个嵌套事务 - isolation=”” 事务隔离级别
4.1 在多线程或并发访问下如何保证访问到的数据具有完整性的.
4.2 脏读:
4.2.1 一个事务(A)读取到另一个事务(B)中未提交的数据,另一个事务中数据可能进行了改变,此时 A事务读取的数据可能和数据库中数据是不一致的,此时认为数据是脏数据,读取脏数据过程叫做脏读.
4.3 不可重复读:
4.3.1 主要针对的是某行数据.(或行中某列)
4.3.2 主要针对的操作是修改操作.
4.3.3 两次读取在同一个事务内
4.3.4 当事务 A 第一次读取事务后,事务 B 对事务 A 读取的淑君进行修改,事务 A 中再次读取的数据和之前读取的数据不一致,过程不可重复读.
4.4 幻读:
4.4.1 主要针对的操作是新增或删除
4.4.2 两次事务的结果.
4.4.3 事务 A 按照特定条件查询出结果,事务 B 新增了一条符合条件的数据.事务 A 中查询的数据和数据库中的数据不一致的,事务 A 好像出现了幻觉,这种情况称为幻读.
4.5 DEFAULT: 默认值,由底层数据库自动判断应该使用什么隔离界别
4.6 READ_UNCOMMITTED: 可以读取未提交数据,可能出现脏读,不重复读,幻读.
4.6.1 效率最高.
4.7 READ_COMMITTED:只能读取其他事务已提交数据.可以防止脏
读,可能出现不可重复读和幻读.
4.8 REPEATABLE_READ: 读取的数据被添加锁,防止其他事务修改
此数据,可以防止不可重复读.脏读,可能出现幻读.
4.9 SERIALIZABLE: 排队操作,对整个表添加锁.一个事务在操作数据时,另一个事务等待事务操作完成后才能操作这个表.
4.9.1 最安全的
4.9.2 效率最低的. - rollback-for=”异常类型全限定路径”
- 5.1 当出现什么异常时需要进行回滚
5.2 建议:给定该属性值.
5.2.1 手动抛异常一定要给该属性值. - no-rollback-for=””
- 6.1 当出现什么异常时不滚回事务.
8. 七. Spring 中常用注解.
-
@Component 创建类对象,相当于配置
-
@Service 与@Component 功能相同.
2.1 写在 ServiceImpl 类上. -
@Repository 与@Component 功能相同.
3.1 写在数据访问层类上. -
@Controller 与@Component 功能相同.
4.1 写在控制器类上. -
@Resource(不需要写对象的 get/set)
5.1 @Resource默认按 byName 自动注入,是J2EE提供的, 需导入Package: javax.annotation.Resource.
5.2 @Resource的作用相当于@Autowired,只不过@Autowired按byType自动注入。
5.3 @Resource有两个中重要的属性:name和type ,而Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。所以如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用 byType自动注入策略。如果既不指定name也不指定type属性,这时将通过反射机制使用byName自动注入策略。 -
@Autowired(不需要写对象的 get/set)
6.1 @Autowired是Spring 提供的,需导入
Package:org.springframework.beans.factory.annotation.Autowired;
只按照byType 注入 -
@Value() 获取 properties 文件中内容
-
@Pointcut() 定义切点
-
@Aspect() 定义切面类
-
@Before() 前置通知
-
@After 后置通知
-
@AfterReturning 后置通知,必须切点正确执行
-
@AfterThrowing 异常通知
-
@Arround 环绕通知
八.Ajax
- 标准请求响应时浏览器的动作(同步操作)
1.1 浏览器请求什么资源,跟随显示什么资源 - ajax:异步请求.
2.1 局部刷新,通过异步请求,请求到服务器资源数据后,通过脚本修改页面中部分内容. - ajax 由 javascript 推出的.
3.1 由 jquery 对 js 中 ajax 代码进行的封装,达到使用方便的效果. - jquery 中 ajax 分类
4.1 第一层 $.ajax({ 属性名:值,属性名:值})
4.1.1 是 jquery 中功能最全的.代码写起来相对最麻烦的.
4.1.2 示例代码
/*
url: 请求服务器地址
data:请求参数
dataType:服务器返回数据类型
error 请求出错执行的功能
success 请求成功执行的功能,function(data) data 服务器返
回的数据.
type:请求方式
*/
$("a").click(function(){
$.ajax({
url:'demo',
data:{"name":"张三"},
dataType:'html',
error:function(){
alert("请求出错.")
},
success:function(data){
alert("请求成功"+data)
},
type:'POST'
});
return false;
})
4.2 第二层(简化$.ajax)
4.2.1 $.get(url,data,success,dataType))
4.2.2
.
p
o
s
t
(
u
r
l
,
d
a
t
a
,
s
u
c
c
e
s
s
,
d
a
t
a
T
y
p
e
)
4.3
第
三
层
(
简
化
.post(url,data,success,dataType) 4.3 第三层(简化
.post(url,data,success,dataType)4.3第三层(简化.get())
4.3.1 $.getJSON(url,data,success). 相 当 于 设 置 $.get 中dataType=”json”
4.3.2 $.getScript(url,data,success) 相 当 于 设 置 $.get 中dataType=”script”
- 如果服务器返回数据是从表中取出.为了方便客户端操作返回的数据,服务器端返回的数据设置成 json
5.1 客户端把 json 当作对象或数组操作. - json:数据格式.
6.1 JsonObject : json 对象,理解成 java 中对象
6.1.1 {“key”:value,”key”:value}
6.2 JsonArray:json 数组
6.2.1 [{“key”:value,”key”:value},{}]