Spring Framework Knowledge Point Two

AOP

1)AOP(Aspect-Oriented Programming): is a new methodology and is passed on
Supplement to the system OOP(Object-Oriented Programming).
Object-oriented vertical inheritance mechanism
Face Oriented Lateral Extraction Mechanism

2) The main object of AOP programming is aspect, which is used for modular cross-cutting concerns (common functions).

3) When applying AOP programming, you still need to define public functions, but you can clearly define where and how this function is applied without modifying the affected classes. This allows cross-cutting concerns to be modularized into special classes, which we often call "slices".

4) Benefits of AOP:
(1) Everything logic is in one place, the code is not scattered, and it is easy to maintain and upgrade
(2) Business modules are simpler and contain only core business codes
(3) AOP Diagram

AspectJ

AspectJ: The most complete and popular AOP framework in the Java community.
In versions above Spring 2.0, you can use AOP based on spectJ annotations or XML configuration.

Enable AspectJ annotation support in Spring
1) Importing JAR packages
com.springsource.net.sf.cglib-2.2.0.jar
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
spring-aop-4.0.0.RELEASE.jar
spring-aspects-4.0.0.RELEASE.jar
2) Introduce aop namespace
3) Configuration

<aop:aspectj-autoproxy>

When the Spring IOC container detects the <aop:aspectj-autoproxy>element in the bean configuration file, it automatically creates a proxy for beans that match AspectJ facets

Declare facets with AspectJ annotations

Declare facets with AspectJ annotations
1) To declare AspectJ facets in Spring, simply declare the facets as bean instances in the IOC container.

2) When AspectJ facets are initialized in the Spring IOC container, the Spring IOC container creates proxies for bean s that match AspectJ facets.

3) In AspectJ annotations, facets are just Java classes with @Aspect annotations, which often contain a lot of notifications.

4) Notifications are simple Java methods labeled with some kind of annotation.

5)AspectJ supports five types of notification annotations:
1@Before: Pre-notification, executed before method execution
(2)@After: Post-notification, executed after method execution
3@AfterRunning: Return notification, execute after method returns result
(4)@AfterThrowing: Exception notification, executed after method throws an exception
_@Around: around notifications, around methods

Entry point expression

Locate one or more specific connection points by expression.

1) Grammatical format of entry point expression

execution([Permission modifier] [return type] [Simple Class Name/Full class name] [Method Name]([parameter list]))

2) In AspectJ, entry point expressions can be combined with operators such as'&','|','!'.

execution (* *.add(int,..)) || execution(* *.sub(int,..))
Meaning	The first parameter in any class is int Type add Method or sub Method

Before advice

1) Pre-Notification: Notification executed before method execution
2) Use the @Before annotation

after returning advise

1) Post Notification: Post Notification is performed after the connection point has completed, i.e. when the connection point returns a result or throws an exception
2) Use the @After comment

Return Notification

1) Return notification: Whether the connection point returns normally or throws an exception, the post-notification is executed. If you only want to log when the connection point returns, you should use a return notification instead of a post-notification.

2) Use the @AfterReturning annotation to access the return value of the connection point in the return notification
(1) In the return notification, the return value of the connection point can be accessed as long as the returning attribute is added to the @AfterReturning annotation. The value of this property is the name of the parameter used to pass in the return value
(2) A parameter with the same name must be added to the signature of the notification method. Spring AOP passes the return value through this parameter at run time
(3) The original tangent expression needs to appear in the pointcut attribute

Exception Notification

1) Exception notification: only execute exception notification when a connection point throws an exception

2) Adding the throwing property to the @AfterThrowing annotation also provides access to exceptions thrown by connection points. Throwable is the top-level parent of all error and exception classes, so any error and exception can be caught in the exception notification method.

3) If you are interested in only one particular exception type, you can declare the parameter as the parameter type of another exception. Notifications are then executed only when exceptions to this type and its subclasses are thrown

Around Advice

1) Surround notification is the most powerful of all notification types, providing full control over connection points and even whether connection points are executed.

2) For surround notifications, the parameter type of the connection point must be ProceedingJoinPoint. It is a subinterface of JoinPoint that allows you to control when and whether connection points are executed.

3) Explicitly call ProceedingJoinPoint's proceed() method to execute the proxied method in the surround notification. If you forget to do this, the notification is executed, but the target method is not executed.

4) Note that the method that surrounds the notification needs to return the result of the target method execution, that is, call joinPoint.proceed(); Otherwise, a null pointer exception will occur.

Specify the priority of the facet

1) When more than one facet is applied at the same connection point, their priority is uncertain unless explicitly specified.
2) The priority of the facet can be specified by implementing the Ordered interface or by using the @Order annotation.
3) To implement the Ordered interface, the smaller the return value of the getOrder() method, the higher the priority.
4) If the @Order comment is used, the serial number appears in the comment

Demonstration case:

aop.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:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
                           http://www.springframework.org/schema/beans/spring-beans.xsd 
                           http://www.springframework.org/schema/aop 
                           http://www.springframework.org/schema/aop/spring-aop.xsd 
                           http://www.springframework.org/schema/context 
                           http://www.springframework.org/schema/context/spring-context.xsd">
    <!-- Scan Component-->
    <context:component-scan base-package="com.spring.aop"/>

    <!-- open aspectj Automatic proxy function-->
    <aop:aspectj-autoproxy/>
</beans>

MathImpl

package com.spring.aop;
import org.springframework.stereotype.Component;

@Component
public class MathImpl implements MathI {
	@Override
	public int add(int i, int j) {
		int result = i + j;
		return result;
	}
	@Override
	public int sub(int i, int j) {
		int result = i - j;
		return result;
	}
	@Override
	public int mul(int i, int j) {
		int result = i * j;
		return result;
	}
	@Override
	public int div(int i, int j) {
		int result = i / j;
		return result;
	}
}

MyloggerAspect Face

package com.spring.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.util.Arrays;

@Component
@Aspect//Label the current class as tangent
@Order(1)//Defines the priority of the slice action. The smaller the value, the higher the priority, and the default value is the maximum value of int
public class MyloggerAspect {

//In AspectJ facets, an entry point can be declared as a simple method through the @Pointcut annotation.
// The method body of the entry point is usually empty because mixing the entry point definition with the application logic is unreasonable.
    @Pointcut(value="execution(* com.spring.aop.*.*(..))")
    public void test() {}

    /**
     * @Before:Specify Method as Pre-Notification
     * value must be set, which is the entry point expression
     * Pre-notification: Acts before method execution
     * @Before(value="execution(* om.spring.aop.*.*(..))")
     * The first * represents any access modifier and return value type
     * The second * represents any class
     * The third * represents any method in the class
     * ..Represents an arbitrary list of parameters
     */
   // @Before (value = "execution (public int com.spring.aop.MathImpl.add (int, int)")//before the specified method
    //@Before(value = "execution(* com.spring.aop. *. * (.))")//before working on all classes under the AOP package and all methods
    @Before(value = "test()")//
    public void brforeMethod(JoinPoint joinPoint){
        Object[] args = joinPoint.getArgs();//Get the parameters for the cut-in method
        String methodName = joinPoint.getSignature().getName();//Get entry method name
        System.out.println("Pre-notification: method:"+methodName+",arguments:"+ Arrays.toString(args));
    }
    /**
     * @After:Label method as post-notification
     * Post-notification: The final statement block that acts on the method, that is, executes regardless of whether there are exceptions
     */
    @After(value = "execution(* com.spring.aop.*.*(..))")
    public void afterMethod(){
        System.out.println("after returning advise");
    }
    /**
     * @AfterReturning:Label method as return notification
     * Return notification: acts after method execution
     * The variable name of the return value of the receive method can be set by returning. To be used in a method, parameters with the same parameter name as the variable name must be set in the method's parameters
     */
    @AfterReturning(value="execution(* com.spring.aop.*.*(..))", returning="result")
    //@AfterReturning(value="test()", returning="result")
    public void afterReturningMethod(JoinPoint joinPoint, Object result) {
        //result is used to receive the return value of the method
        String methodName = joinPoint.getSignature().getName();
        System.out.println("Return notification: method:"+methodName+",result:"+result);
    }

    /**
     * @AfterThrowing:Label method as exception notification (exception notification)
     * Exception Notification: When an exception is thrown by a method
     * The exception information returned by the receive method can be set by throwing, and the specified exception information can be manipulated by specific exception types in the parameter list.
     */
    @AfterThrowing(value = "execution(* com.spring.aop.*.*(..))",throwing = "ex")
    public void afterThrowingMethod(Exception ex){
        System.out.println("Has an exception,message:"+ex);
    }

//    @Around(value="execution(* com.spring.aop. *. *(.))")//Less used
//    public Object aroundMethod(ProceedingJoinPoint joinPoint) {
//
//        Object result = null;
//
//        try {
//            //Pre-notification
//            System.out.println("Around:Before");
//            result = joinPoint.proceed();// Execution Method
//            //Return Notification
//            System.out.println("Around:AfterReturning");
//            return result;
//        } catch (Throwable e) {
//            // TODO Auto-generated catch block
//            e.printStackTrace();
//            //Exception Notification
//            System.out.println("Around:AfterThrowing");
//        } finally {
//            //Post Notification
//            System.out.println("Around:After");
//        }
//
//        return -1;
//    }
}

TestHandler Face

package com.spring.aop;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Component
@Aspect
@Order(0)
public class TestHandler  {
    @Before(value="execution(* com.spring.aop.*.*(..))")
    public void before() {
        System.out.println("TestHandler==>Before advice");
    }
}
public class TestAOP {
    public static void main(String[] args) {

        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("aop.xml");
        MathI mathImpl = applicationContext.getBean("mathImpl", MathI.class);
        //Note: This is not MathImpl.class because it uses a dynamic proxy and is invoked through an interface.
        mathImpl.add(1,2);
        System.out.println("------------------------");
        mathImpl.sub(4,2);
        System.out.println("------------------------");
        mathImpl.div(1,0);
    }
}

Test results:

Configuring facets in XML

In addition to declaring facets using AspectJ annotations, Spring also supports declaring facets in the bean configuration file. This declaration is made through an XML element in the aop namespace.
Normally, annotation-based declarations take precedence over XML-based declarations. AspectJ annotations allow facets to be compatible with AspectJ, while XML-based configurations are Spring-specific. Since AspectJ is increasingly supported by AOP frameworks, facets written in annotation style will have more opportunities for reuse.

<?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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">


    <context:component-scan base-package="com.spring.aopxml"></context:component-scan>

    <aop:config>
        <aop:aspect ref="myLogger">
            <aop:pointcut id="cut" expression="execution(* com.spring.aopxml.*.*(..))"/>
             <!-- <aop:before method="before" pointcut="execution(* com.spring.aopxml.*.*(..))"/>-->
            <aop:before method="before" pointcut-ref="cut"/>
        </aop:aspect>

    </aop:config>
</beans>
package com.spring.aopxml;
import org.springframework.stereotype.Component;
@Component
public class MyLogger {

    public void before(){
        System.out.println("Before advice:");
    }
}
package com.spring.aopxml;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class test {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("aopxml.xml");
        MathI mathImpl = applicationContext.getBean("mathImpl", MathI.class);
        System.out.println(mathImpl.add(12,12));
    }
}

JdbcTemplate

To make JDBC easier to use, Spring defines an abstraction layer on the JDBC API to establish a JDBC access framework.
As the core of the Spring JDBC framework, JDBC templates are designed to provide template methods for different types of JDBC operations, which minimize the workload of database access while preserving as much flexibility as possible.
You can think of Spring's JdbcTemplate as a small lightweight persistence layer framework, very similar to the DBUtils style we've used before.

Environmental preparation
Import JAR Package
1) JAR package required by IOC container
commons-logging-1.1.1.jar
spring-beans-4.0.0.RELEASE.jar
spring-context-4.0.0.RELEASE.jar
spring-core-4.0.0.RELEASE.jar
spring-expression-4.0.0.RELEASE.jar

2) JAR package required by JdbcTemplate
spring-jdbc-4.0.0.RELEASE.jar
spring-orm-4.0.0.RELEASE.jar
spring-tx-4.0.0.RELEASE.jar

3) Database Drivers and Data Sources
druid-1.1.9.jar
mysql-connector-java-5.1.7-bin.jar

Persistence operation

First configure the file:

<!--    Introducing resource files-->
    <context:property-placeholder location="db.properties"></context:property-placeholder>

<!--    create data source-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <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>

<!--    Configuring from a data source jdbctemplate-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>


Obtain jdbctemplate object from IOC container

ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("jdbc.xml");
    JdbcTemplate jdbcTemplate = applicationContext.getBean("jdbcTemplate", JdbcTemplate.class);

Add, delete and change

Add or delete:

  @Test
    public void test(){
        //JdbcTemplate.update ("insert into EMP values (null,'guo chao','21','man')));
        String sql="insert into emp values(null,?,?,?)";
        jdbcTemplate.update(sql,"Li Si",24,"female");

        //Note that batch deletion or modification via update, where... In (?) mode, cannot be assigned with wildcards
        String deletesql="delete from emp where eid in (?)";
        String eids="1,2,3";
        jdbcTemplate.update(deletesql,eids);//No matter how many times you execute, the end result is simply deleting rows of eid=1
        /*Assigning wildcards is done by calling the setString method of preparestatement, which assigns values to strings?
        However, varchar data types are single quoted in databases, so the setString method automatically adds single quotes to characters - by default, single quotes are placed on both sides of wildcards
        So the final sql statement above changes to delete from emp where eid in ('1,2,3')
        This can be done with the following code:
        String eid="1,2,3";
        String sql ="delete from emp where eid in (+eid+)";
        jdbcTemplate.update(sql);*/

        //Similarly, fuzzy queries cannot use wildcards: select* from emp where ename like'%?%', For the same reason
    }

Bulk add-delete change

@Test
    public void testBatchUpdate(){
           //int a[]=new int[]{1,2,3};
        String sql="insert into emp values(null,?,?,?)";
        ArrayList<Object[]> list = new ArrayList<>();
        list.add(new Object[]{"a1",1,"male"});
        list.add(new Object[]{"a2",2,"male"});
        list.add(new Object[]{"a3",3,"male"});
        jdbcTemplate.batchUpdate(sql,list);//Bulk Modification

    }

query

@Test
    public void testqueryforobject() {
        // jdbcTemplate.queryForObject(sql,requiredType); Used to get a single value
        // jdbcTemplate.queryForObject(sql,rowMapper); Used to get a single piece of data
        String sql = "select ename,age,sex,eid from emp where eid=?";
        BeanPropertyRowMapper<Emp> rowMapper = new BeanPropertyRowMapper<>(Emp.class);//Mapping column names (field names or aliases of fields) to attribute names of classes must be the same as attribute names in classes for successful assignment
        Emp emp = jdbcTemplate.queryForObject(sql, new Object[]{1}, rowMapper);
        System.out.println(emp);

        String sql2 = "select count(*) from emp";
        Integer count = jdbcTemplate.queryForObject(sql2, Integer.class);
        System.out.println(count);

        String sql3 = "select ename,age,eid,sex from emp";
        List<Emp> list = jdbcTemplate.query(sql3, rowMapper);
        for (Emp emplist : list) {
            System.out.println(emplist);
        }
    }

Transaction issues

A transaction is a set of database operations that are logically tightly related and merged into a whole (unit of work), either all or none of which are performed.

Spring Transaction Management

Programmatic Transaction Management

1) Transaction management using native JDBC API s
1. Get the database Connection connection object
(2) Cancel the automatic commit of transactions
(3) Perform operations
(4) Manual transaction submission when normal operation is completed
Roll back transaction when execution fails
Close related resources

2) Evaluation
Transaction management using native JDBC API is the cornerstone of all transaction management methods and the most typical programmatic transaction management. Programmatic transaction management requires embedding transaction management code into business methods to control transaction submission and rollback. When managing transactions programmatically, additional transaction management code must be included in each transaction operation. Transaction management code is obviously non-core compared to core business. If multiple modules use the same mode of code for transaction management, it will obviously cause a greater degree of code redundancy.

Declarative Transaction Management

In most cases, declarative transactions are better than programmatic transaction management: they separate transaction management code from business methods to implement transaction management declaratively.

The fixed pattern of transaction management code, as a cross-cutting focus, can be modularized through the AOP method and then implemented through the Spring AOP framework for declarative transaction management.
Spring defines an abstraction layer on top of different transaction management APIs that can be configured to work so that application developers do not have to know the underlying implementation details of the transaction management API to use Spring's transaction management mechanisms.
Spring supports both programmatic and declarative transaction management.

Transaction Manager provided by Spring

Spring abstracts a set of transaction management mechanisms from different transaction management API s, allowing transaction management code to be isolated from specific transaction technologies. Developers manage transactions configuratively without having to know how their underlying layers are implemented.
Spring's core transaction management abstraction is that it encapsulates a set of technology-independent methods for transaction management. No matter which transaction management strategy Spring uses (programmatic or declarative), a transaction manager is required.

Transaction managers can be declared in the Spring IOC container as ordinary bean s.
The main implementation of Transaction Manager:
1)DataSourceTransactionManager: Only one data source needs to be processed in the application and accessed through JDBC.
2) JtaTransaction Manager: Transaction management with JTA(Java Transaction API) on JavaEE application servers
3)HibernateTransactionManager: Accessing databases using the Hibernate framework

Propagation behavior of transactions

When a transaction method is called by another transaction method, you must specify how the transaction should propagate. For example, a method may continue to run in an existing transaction, or it may open a new transaction and run in its own transaction.
The propagation behavior of a transaction can be specified by the propagation property. Spring defines seven types of propagation behavior.

Transaction propagation properties can be defined in the propagation property of the @Transactional annotation.

Explain
(1) REQUIRED Propagation Behavior
When bookService's purchase() method is called by another transaction method, checkout (), it runs within an existing transaction by default. This default propagation behavior is REQUIRED. Therefore, there is only one transaction within the start and end boundaries of the checkout() method. The transaction is committed only at the end of the checkout() method, and the user cannot buy a book.

REQUIRES_NEW Propagation Behavior
Indicates that the method must start a new transaction and run within its own transaction. If a transaction is running, it should be suspended first.

Transaction isolation level

Database Transaction Concurrency Problems
Suppose you now have two transactions: Transaction01 and Transaction02 executed concurrently.
1) Dirty reading
Transaction01 changes the AGE value of a record from 20 to 30.
(2) Transaction02 read the updated value of Transaction01: 30.
(3) Transaction01 rolled back and the AGE value was restored to 20.
(4) The 30 read by Transaction02 is an invalid value.
2) Non-repeatable reading
Transaction01 read an AGE value of 20.
Transaction02 modifies the AGE value to 30.
(3) Transaction01 reads AGE value 30 again, which is inconsistent with the first read.
3) Illusional Reading
Transaction01 read part of the data in the STUDENT table.
Transaction02 inserts new rows into the STUDENT table.
(3) Transaction01 read the STUDENT table with some more rows.

Timeout and read-only properties of transactions

Since transactions can acquire locks on rows and tables, long transactions can consume resources and affect overall performance.
If a transaction reads data without modification, the database engine can optimize the transaction.

Timeout Transaction Property: How long a transaction can persist before a forced rollback is enforced. This prevents long-running transactions from consuming resources.
Read-only transaction property: Indicates that this transaction reads data only but does not update it, which helps the database engine optimize transactions.

Transaction Summary (Source Code Test)

Configuring transactions through aspectj annotations

book.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: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/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">


    <context:component-scan base-package="com.spring.book"></context:component-scan>
    <!--    Introducing resource files-->
    <context:property-placeholder location="db.properties"></context:property-placeholder>

    <!--    create data source-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <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>

    <!--    Configuring from a data source jdbctemplate-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

<!--Configure Transaction Manager-->
    <bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="dataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

  <!-- Turn on annotation-driven, which scans transaction-related annotations, parses meaning, and performs functions-->
   <!--adopt aspectJ To configure-->
<tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>

</beans>

BookDaoImpl

package com.spring.book.dao;
import com.spring.book.MyException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

@Repository
public class BookDaoImpl implements BookDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;
    
    @Override
    public Integer selectPrice(String bid) {
        Integer price = jdbcTemplate.queryForObject("select price from book where bid=?", new Object[]{bid}, Integer.class);
        return price;
    }
    @Override
    public void updateSt(String bid) {
        //Get a Book Inventory
        Integer integer = jdbcTemplate.queryForObject("select st from stock where sid=?", new Object[]{bid}, Integer.class);
        if (integer<=0){
            throw new RuntimeException();
        }else {
            jdbcTemplate.update("update stock set st=st-1 where sid=?",bid);
        }

    }
    @Override
    public void updateBalance(String uid ,Integer price) {
        Integer integer = jdbcTemplate.queryForObject("select balance from customer where uid=?", new Object[]{uid}, Integer.class);
        if (integer<price){
            throw new MyException();
        }else{
            jdbcTemplate.update("update customer set balance=balance-? where uid=? ",price,uid);
        }

    }
}

BookServiceImpl

package com.spring.book.service;

import com.spring.book.MyException;
import com.spring.book.dao.BookDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
//@Transactional
public class BookServiceImpl implements BookService {
    @Autowired
    private BookDao bookDao;

    /**
     * @Transactional : Manage all operations in a method as a transaction
     * In the method, only the method is valid; Used on a class, works for all methods in the class
     *@Transactional Properties that can be set in:
     *
     * propagation: A Both method and method B have transactions. When method A calls method B, it propagates the transactions in method A to method B. The way method B handles transactions is the propagating behavior of transactions.
     *Propagation.REQUIRED:The caller's transaction must be used (default)
     *Propagation.REQUIRES_NEW:Suspend the caller's transaction, do not use the caller's transaction, use the new transaction to process
     *
     * isolation: Transaction isolation level, a specification for manipulating data in concurrent situations
     *                Read Uncommitted: Dirty Read 1
     *                Read submitted: non-repeatable read 2
     *                Repeatable Read: Magic Read 4
     *                Serialization: Low performance, high consumption 8
     *
     * timeout:Maximum time that can be executed (waited) before a transaction is forced to rollback
     *
     *  readOnly:Specifies whether a series of operations in the current transaction are read-only
     *If set to read-only, mysql will not lock when requesting access to data, regardless of whether there are write operations in the transaction, improving performance
     *However, if there are write operations, it is recommended that you do not set read-only (it is only useful to set true when all operations are read)
     *
     *
     *  ollbackFor|rollbackForClassName|noRollbackFor|noRollbackForClassName:Set conditions for transaction rollback
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW,timeout = 3,rollbackFor = {NullPointerException.class, MyException.class})//Force rollback if the transaction has not completed within three seconds
    //Transaction management through the @Transactional annotation
    public void buyBook(String bid, String uid) {//The propagator is checkOutbook()

//        try {
//            Thread.sleep(2000);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }

        //Next three actions are either all or none
        Integer price = bookDao.selectPrice(bid);//Query price
        bookDao.updateSt(bid);//Update book inventory
        bookDao.updateBalance(uid,price);//Update user balance
    }
}

CashierServiceImpl

package com.spring.book.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;

@Service
@Transactional
public class CashierServiceImpl implements  Cashier {

    @Autowired
    private  BookService service;

    @Override
    public void checkOut(String uid, List<String> bids) {
        for (String bid :
                bids) {
            service.buyBook(bid,uid);//checkout transaction propagates to buybook transaction
        }
    }
}

BookController

package com.spring.book.controller;
import com.spring.book.service.BookService;
import com.spring.book.service.Cashier;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

import java.util.ArrayList;

@Controller
public class BookController {

    @Autowired
    private BookService bookService;
    @Autowired
    private Cashier cashier;
    public void buybook(){
        bookService.buyBook("1","1001");
    }

    public void checkOut(){
        ArrayList<String> bids = new ArrayList<>();
        bids.add("1");
        bids.add("2");
        cashier.checkOut("1001",bids);
    }
}
public class test {

    public static void main(String[] args) {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("book.xml");
        BookController controller = applicationContext.getBean("bookController", BookController.class);
       // controller.buybook();
        controller.checkOut();
    }
}
Configuring transactions through 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.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">

	<context:component-scan base-package="com.atguigu.book_xml"></context:component-scan>
	
	<!-- Introducing a property file -->
	<context:property-placeholder location="db.properties"/>

	<!-- create data source -->
	<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
		<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>

	<!-- Configuring from a data source JdbcTemplate -->
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	
	<!-- Configure the transaction manager, whether annotated or xml To configure transactions in a way, you must have DataSourceTransactionManager Transaction Manager Support -->
	<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	
	<!-- Configure Transaction Notifications -->
	<tx:advice id="tx" transaction-manager="dataSourceTransactionManager">
		<tx:attributes>
			<!-- Set up the transaction again under the set entry point expression -->
			<tx:method name="buyBook"/>
			<tx:method name="checkOut"/>
			
			<!-- only select The method at the beginning will be transacted -->
			<tx:method name="select*" read-only="true"/>
			<tx:method name="insert*"/>
			<tx:method name="update*"/>
			<tx:method name="delete*"/>
			
			<tx:method name="*"/>
			
		</tx:attributes>
	</tx:advice>

	<!-- Configure entry point expressions -->
	<aop:config>
		<aop:pointcut expression="execution(* com.atguigu.book_xml.service.impl.*.*(..))" id="pointCut"/>
		<aop:advisor advice-ref="tx" pointcut-ref="pointCut"/>
	</aop:config>
	
</beans>

Keywords: Java Spring Back-end

Added by jozard on Wed, 08 Dec 2021 06:55:51 +0200