Spring学习day-65:事务和注解

2019-10-22  本文已影响0人  开源oo柒

一、Spring中的TX事务

1.为什么使用事务?

当时学习mybatis的时,mybatis中的事务和JDBC事务是一致的,那么Spring中式如何进行事务管理的呢?

2.事务管理方式:

(1)编程式事务管理:整个事务管理都是需要程序员自己手动编写,自己提交或者回滚 。
(2)声明式事务管理:就是整个事务的管理操作,不需要我们自己书写,现在Spring已经帮你处理好了,我们自己只要代码中声明配置即可。

3.事务管理的应用场景:

当我们执行的式两条或者两条以上的添加、修改、删除的操作时才使用事务。

(1)原子性(atomicity):一个事务必须视为一个不可分割的最小工作单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚,对于一个事务来说,不可能只执行其中的一部分操作,这就是事务的原子性。
(2)一致性(consistency):数据库总数从一个一致性的状态转换到另一个一致性的状态。
(3)隔离性(isolation):一个事务所做的操作(添加、修改、删除)在最终提交以前,对其他事务是不可见的。
(4)持久性(durability):一旦事务提交,则其所做的操作(添加、修改、删除)就会永久保存到数据库中。此时即使系统崩溃,修改的数据也不会丢失。

4.Spring中声明式事务:

给方法增加事务 就是给切点增加通知 。
(1)切点:需要的方法(一般在Service层);
(2)通知:事务;
(3)构成切面;

<!--声明事务的对象-->    
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">        
    <property name="dataSource" ref="ds"></property>    
</bean>    
<tx:advice id="ad" transaction-manager="transactionManager">        
  <tx:attributes>            
    <tx:method name="login" />        
  </tx:attributes>    
</tx:advice>    
<!--通过配置切面的方式增加通知-->        
<aop:config>                
    <aop:pointcut id="pt" expression="execution(* com.zlw.service.impl.AdminServiceImpl.*(..))"></aop:pointcut>        
    <aop:advisor advice-ref="ad" pointcut-ref="pt"> </aop:advisor>            
</aop:config>

5.事务管理的配置属性:

(1)name="":哪些方法需要有事务控制;
(2) readonly="boolean":是否是只读事务(如果为true,告诉数据库此事务为只读事务;如果为false(默认值),事务需要提交的事务.建议新增,删除,修改)。
(3)propagation:控制事务传播行为;当一个具有事务控制的方法被另一个有事务控制的方法调用后,需要如何管理事务;

(REQUIRED (默认值): 如果当前有事务,就在事务中执行,如果当前没有事务,新建一个事务;
SUPPORTS:如果当前有事务就在事务中执行,如果当前没有事务,就在非事务状态下执行。
MANDATORY:必须在事务内部执行,如果当前有事务,就在事务中执行,如果没有事务,报错。)

(4)isolation="":事务隔离级别;在多线程或并发访问下如何保证访问到的数据具有完整性的。

( DEFAULT: 默认值,由底层数据库自动判断应该使用什么隔离界别;
SERIALIZABLE: 排队操作,对整个表添加锁.一个事务在操作数据时,另一个事务等待事务操作完成后才能操作这个表。最安全的,效率最低的。

(5) rollback-for="异常类型全限定路径":当出现什么异常时需要进行回滚;手动抛异常一定要给该属性值。
(6)no-rollback-for="" :当出现什么异常时不滚回事务。

二、Spring中的注解

1.Spring中常见注解:

(1)@Component 创建类对象,相当于配置<bean/>; bean的ID默认为类名首字母小写,也可以指定ID,例如@Component("stu") 。
(2)@Service 与@Component功能相同;写在ServiceImpl类上。
(3)@Repository 与@Component功能相同;写在数据访问层类上。
(4)@Controller 与@Component功能相同;写在控制器类上。
(5)@Resource(不需要写对象的get/set),java中的注解,默认按照byName注入,如果没有名称对象,按照byType注入;建议把对象名称和spring容器中对象名相同 。
(6)@Autowired(不需要写对象的get/set):spring的注解,默认按照byType注入。
(7)@Value():获取properties文件中内容。
(8)@Pointcut() 定义切点 ;@Aspect() 定义切面类 ;@Before() 前置通知 ;@After 后置通知;@AfterReturning 后置通知,必须切点正确执行;@AfterThrowing 异常通知;@Arround 环绕通知 。

使用注解时,一定要在配置文件中声明注解扫描 。

 <context:component-scan base-package="包名路径"></context:component-scan>         
  <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
package com.zlw.advice;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class AspectJAdvice {
    //前置通知方法
    @Before("execution(* com.zlw.pojo.User.a())")
    public void before(){
        System.out.println("前置通知!");
    }
    //环绕通知方法
    @Around("execution(* com.zlw.pojo.User.a())")
    public Object around(ProceedingJoinPoint point)throws Throwable{
        System.out.println("环绕通知:前...");
        Object o = point.proceed();
        System.out.println("环绕通知:后...");
        return o;
    }
    //后置通知方法
    @After("execution(* com.zlw.pojo.User.a())")
    public void after(){
        System.out.println("后置通知!");
    }
    //异常通知方法
    @AfterThrowing("execution(* com.zlw.pojo.User.a())")
    public void throwsAd(){
        System.out.println("异常通知!");
    }
}

(2)切点:

@Component("us")
public class User {
    public void a() {
        System.out.println("方法A()");
    }

(3)ApplicationContext文件配置:

        <!-- 扫描注解 -->
        <context:component-scan base-package="com.zlw.pojo,com.zlw.advice"></context:component-scan>
        
        <!-- 扫描的是 @Aspect -->
       <aop:aspectj-autoproxy> </aop:aspectj-autoproxy>

(4)测试:

package com.zlw.test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.zlw.pojo.User;

public class Test01 {
    public static void main(String[] args) {
        ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
        User user = app.getBean("us",User.class);
        user.a();
    }
}
结果

三、银行转账系统

1.需求:

(1)实现转账账号和密码的校验;
(2)实现转账金额的校验;
(3)实现收款人的账号校验;
(4)实现Spring的事务管理;
(5)使用的技术:Spring + mybatis+jsp+servlet ;

2.实现步骤:

create table account(
    id int(5) PRIMARY KEY auto_increment,
    cno VARCHAR(50),
    pwd VARCHAR(50),
    money int(5)
)

(1)查询:
select * from account where cno=? and pwd =?
select * from account where cno=? and pwd =? and money>=#{param1}
select * from account where cno =?
(2)修改账号金额:
update account set money=money-#{} where cno=#{}
update account set money =money+#{} where cno =#{}

    private int id;
    private String cno;
    private String pwd;
    private int money;
<?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.zlw.mapper.AccountMapper">

    <select id="selOne" resultType="account">
        select * from account
        <where>
            <if test="param1!=null and param1!=''">
                cno = #{param1}
            </if>

            <if test="param2!=null and param2!=''">
                and pwd = #{param2 }
            </if>

            <if test="param3!=null and param3!=''">
                and money >= #{param3 }
            </if>
        </where>
    </select>
    <update id="update">
        update account set money = money-#{1} where cno = #{0}
    </update>
    <update id="update2">
        update account set money = money+#{1} where cno = #{0}
    </update>
</mapper>
<?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:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd 
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
        <!-- 获取数据源 -->
        <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
            <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
            <property name="url" value="jdbc:mysql://localhost:3306/user"></property>
            <property name="username" value="root"></property>
            <property name="password" value="root"></property>
        </bean>
        <!-- SqlSessionFactory -->
        <bean id="factory" class="org.mybatis.spring.SqlSessionFactoryBean">
            <property name="dataSource" ref="dataSource"></property>
            
            <property name="typeAliasesPackage" value="com.zlw.pojo"></property>
        </bean>
        <!-- 扫描mapper -->
        <bean id="mapper" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
            <property name="sqlSessionFactoryBeanName" value="factory"></property>
            <property name="basePackage" value="com.zlw.mapper"></property>
        </bean>
        
        <!-- 配置注解的扫描 -->
        <context:component-scan base-package="com.zlw.service.impl"></context:component-scan>
    
        <!-- 配置声明式事务 -->
        <!--  
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"></property>
        </bean>
        -->
        <!-- 扫描事务注解 -->
        <!--  
        <tx:annotation-driven ></tx:annotation-driven>
        -->
</beans>        
package com.zlw.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.zlw.mapper.AccountMapper;
import com.zlw.pojo.Account;
import com.zlw.service.AccountService;

@Service("accountService")
public class AccountServiceImpl implements AccountService {
    
    @Autowired
    private AccountMapper accountMapper;

    //查询指定账户
    @Override
    public Account findOne(String cno, String pwd, int money) {
        return accountMapper.selOne(cno, pwd, money);
    }

    //修改账户金额
    @Override
    @Transactional
    public int updateMoney(String inCno, String outCno, int money) {
        int n = accountMapper.update(outCno, money);
        int n2 = accountMapper.update2(inCno, money);
        
        if (n > 0 && n2 > 0) {
            return 1;
        }
        return 0;
    }
}
package com.zlw.controller;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.zlw.pojo.Account;
import com.zlw.service.AccountService;

public class AccountServlet extends HttpServlet {

    AccountService accs ;
    
    @Override
    public void init() throws ServletException {
        ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
        accs = app.getBean("accountService",AccountService.class);
    }
    
    //判断请求信息
    public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String method = request.getParameter("method");
        if ("checkUser".equals(method)) {
            checkUser(request,response);
        }else{
            updateMoney(request,response);
        }
    }

    private void updateMoney(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
        //获取页面信息
        String cno = request.getParameter("cno");
        String cno2 = request.getParameter("cno2");
        
        String mo = request.getParameter("money");
        int money = 0;
        if(mo!=null&&mo!=""){
            money = Integer.parseInt(mo);
        }
        //处理
        int n = accs.updateMoney(cno2, cno, money);
        
        if(n>0){
            response.sendRedirect(request.getContextPath()+"/success.jsp");
        }else{
            request.setAttribute("error", "转账失败!");
            request.getRequestDispatcher("/account.jsp").forward(request, response);
        }
    }
    
    private void checkUser(HttpServletRequest request, HttpServletResponse response) throws IOException {
        //接收页面数据
        String cno = request.getParameter("cno");
        String pwd = request.getParameter("pwd");
        String my = request.getParameter("money");
        System.out.println(my);
        int money =0 ;
        if(my!=null&&my!=""){
            money = Integer.parseInt(my);
        }
        System.out.println(cno+"---"+pwd+"--"+money);
        //处理信息
        Account account = accs.findOne(cno, pwd, money);
    
        //响应
        if(account!=null){
            response.getWriter().println("true");
        }else{
            response.getWriter().println("false");
        }
    }
    
}
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
    String path = request.getContextPath();
    String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort()
            + path + "/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">

<title>银行转账系统</title>
<script type="text/javascript" src="js/jquery-1.12.3.min.js"></script>
<script type="text/javascript">
    var flage1 = false;
    var flage2 = false;
    var flage3 = false;

    $(function() {
        //校验账户
        $("#inp1").blur(function() {
            var cno = $("#inp").val();
            var pwd = $("#inp1").val();
            //发送ajxa请求
            $.post("accountServlet?method=checkUser", "cno=" + cno + "&pwd=" + pwd, function(re) {

                if (re) {
                    flage1 = true;
                    $("#inp1_span").html("√ 汇款人信息正确!").css("color", "green");
                } else {
                    $("#inp1_span").html("X 汇款人信息错误!").css("color", "red");
                }
            }, "json")
        })
        //判断金额
        $("#inp2").blur(function() {
            var cno = $("#inp").val();
            var pwd = $("#inp1").val();
            var money = $("#inp2").val();

            $.post("accountServlet?method=checkUser", "cno=" + cno + "&pwd=" + pwd + "&money=" + money, function(data1) {

                if (data1) {
                    flage2 = true;
                    $("#inp2_span").html("√ 汇款金额正确!").css("color", "green");
                } else {
                    $("#inp2_span").html("X 汇款金额错误!").css("color", "red")
                }

            }, "json")
        })
        //判断收款人信息
        $("#inp3").blur(function() {
            var cno2 = $("#inp3").val();
            var cno = $("#inp").val();

            if (cno == cno2) {
                alert("两个账号不能相同!")
            } else {
                $.post("accountServlet?method=checkUser", "cno=" + cno2, function(data) {
                    if (data) {
                        flage3 = true;
                        $("#inp3_span").html("√ 收款人信息正确!").css("color", "green");
                    } else {
                        $("#inp3_span").html("X 收款人信息错误!").css("color", "red");
                    }
                }, "json");
            }
        });
    })
    
    function change() {
        if (flage1 && flage2 && flage3) {
            return true;
        }
        return false;
    }
</script>
</head>

<body>
    <h3>银行转账系统</h3>
    <span style="color: red"> ${error }</span>
    <form action="accountServlet?method=updateMoney" method="post"
        onsubmit="return change()">
        <p>
            转账账号:<input type="text" id="inp" name="cno" />
        </p>
        <p>
            账号密码:<input type="text" id="inp1" /><span id="inp1_span"></span>
        </p>
        <p>
            转账金额:<input type="text" id="inp2" name="money" /><span
                id="inp2_span"></span>
        </p>
        <p>
            收款账号:<input type="text" id="inp3" name="cno2" /><span id="inp3_span"></span>
        </p>
        <p>
            <input type="submit" value="转账" />
        </p>
    </form>
</body>
</html>

3.实现效果:

所有信息都正确
账号或密码错误
金额错误
收款账号错误
成功页面

四、Spring总结:

1.Spring IOC(控制反转):

作用:帮助我们创捷对象的,进行代码之间的解耦;
IOC实现方式{无参构造;有参构造 ;工厂模式} ;
DI:依赖注入;给创建好的全局属性或者对象进行赋值 ;
DI注入方式:{有参构造;set方法;自动注入} ;

2.Spring AOP(面向切面编程):

代理模式{静态代理 动态代理-[JDK代理、CGLIB代理]} ;
OP作用:提升代码的扩展性 、进行了代码的解耦;
AOP的实现方式:(schema base,aspectJ);

3.Spring TX(声明式事务):

编程式事务、声明式事务;

4.Spring中的注解:

(1)创建对象 :@Component @Service @Controller ;
(2)进行值得注入: @Resource @Autowired ;
(3)AspectJ的注解: @Aspect @Befor ...
(4) 声明式事务注解 @Transactional ;

<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

(2)事务:

<tx:annotation-driven></tx:annotation-driven>
上一篇下一篇

猜你喜欢

热点阅读