Learn Spring - JdbcTemplate and Spring transactions from scratch

1. jdbcTemplate

1.1 basic concepts

  • JdbcTemplate is a template object provided in the spring framework. It is a simple encapsulation of the original cumbersome Jdbc API object

  • Core object

    JdbcTemplate jdbcTemplate = new JdbcTemplate(DataSource dataSource);
    
  • Core method

    Execute addition, deletion and modification statements 
    int update(); 
    // //Query multiple
    List<T> query(); 
    // Query one 
    T queryForObject(); 
    // Implement ORM mapping encapsulation
    new BeanPropertyRowMapper<>(); 
    

1.2 Spring integration

1.2.1 Maven configuration

  <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.25</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.8</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.15</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.7</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.3.15</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>5.3.15</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.3.15</version>
        </dependency>
    </dependencies>

1.2.2 entity class

  • Account

    public class Account {
    
        private Integer id;
        private String name;
        private Double money;
        
    }
    

1.2.3 Dao layer interface

  • AccountDao

    package cn.knightzz.dao;
    
    import cn.knightzz.entity.Account;
    
    import java.util.List;
    
    public interface AccountDao {
    
        /**
         * Query all accounts
         * @return
         */
        public List<Account> findAll();
    
        /**
         * Query account by id
         * @param id
         * @return
         */
        public Account findById(Integer id);
    
        /**
         * Add account information
         * @param account
         */
        public void save(Account account);
    
        /**
         * Update account information
         * @param account
         */
        public void update(Account account);
    
        /**
         * Delete account information
         * @param id
         */
        public void delete(Integer id);
    }
    
    
  • AccountDaoImpl

    package cn.knightzz.dao.impl;
    
    import cn.knightzz.dao.AccountDao;
    import cn.knightzz.entity.Account;
    import org.springframework.beans.factory.BeanFactory;
    import org.springframework.jdbc.core.BeanPropertyRowMapper;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.stereotype.Repository;
    
    import javax.annotation.Resource;
    import java.util.List;
    
    /**
     * @author Wang Tianci
     * @title: AccountDaoImpl
     * @projectName mybatis-apply-06
     * @description:
     * @website http://knightzz.cn/
     * @github https://github.com/knightzz1998
     * @date 2022/1/27 14:07
     */
    @Repository("accountDao")
    public class AccountDaoImpl implements AccountDao {
    
        @Resource
        JdbcTemplate jdbcTemplate;
    
        @Override
        public List<Account> findAll() {
    
            String sql = "select * from account";
            List<Account> accountList = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(Account.class));
            return accountList;
        }
    
        @Override
        public Account findById(Integer id) {
    
            String sql = "select * from account where id = ?";
            Account account = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(Account.class), id);
            return account;
        }
    
        @Override
        public void save(Account account) {
            String sql = "insert into account(id, name ,money) values(null ,  ?,  ?)";
            jdbcTemplate.update(sql, account.getName(), account.getMoney());
        }
    
        @Override
        public void update(Account account) {
            String sql = "update account set name = ?, money = ? where id = ?";
            jdbcTemplate.update(sql, account.getName(), account.getMoney(), account.getId());
        }
    
        @Override
        public void delete(Integer id) {
            String sql = "delete from account where id = ?";
            jdbcTemplate.update(sql, id);
        }
    }
    
    
    

1.3.4 Service layer interface

  • AccountService interface

    package cn.knightzz.service;
    
    import cn.knightzz.entity.Account;
    
    import java.util.List;
    
    public interface AccountService {
        /**
         * Query all accounts
         * @return
         */
        public List<Account> findAll();
    
        /**
         * Query account by id
         * @param id
         * @return
         */
        public Account findById(Integer id);
    
        /**
         * Add account information
         * @param account
         */
        public void save(Account account);
    
        /**
         * Update account information
         * @param account
         */
        public void update(Account account);
    
        /**
         * Delete account information
         * @param id
         */
        public void delete(Integer id);
    
    
    }
    
  • AccountServiceImpl

    package cn.knightzz.service.impl;
    
    import cn.knightzz.dao.AccountDao;
    import cn.knightzz.entity.Account;
    import cn.knightzz.service.AccountService;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.Resource;
    import java.util.List;
    
    @Service("accountService")
    public class AccountServiceImpl implements AccountService {
    
        @Resource
        AccountDao accountDao;
    
        @Override
        public List<Account> findAll() {
            return accountDao.findAll();
        }
    
        @Override
        public Account findById(Integer id) {
            return accountDao.findById(id);
        }
    
        @Override
        public void save(Account account) {
            accountDao.save(account);
        }
    
        @Override
        public void update(Account account) {
            accountDao.update(account);
        }
    
        @Override
        public void delete(Integer id) {
            accountDao.delete(id);
        }
    }
    
    

1.3.5 test code

  • AccountServiceTest

    package cn.knightzz.service;
    
    import cn.knightzz.config.SpringConfig;
    import cn.knightzz.entity.Account;
    import junit.framework.TestCase;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    import javax.annotation.Resource;
    import java.util.List;
    
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = {SpringConfig.class})
    public class AccountServiceTest extends TestCase {
    
        @Resource
        AccountService accountService;
    
        @Test
        public void testFindAll() {
            List<Account> accountList = accountService.findAll();
            for (Account account : accountList) {
                System.out.println(account);
            }
        }
    
        @Test
        public void testFindById() {
            Account account = accountService.findById(1);
            System.out.println(account);
        }
    
        @Test
        public void testSave() {
            Account accout = new Account();
            accout.setId(3);
            accout.setName("kiss");
            accout.setMoney(300d);
            accountService.save(accout);
        }
    
        @Test
        public void testUpdate() {
            Account accout = new Account();
            accout.setId(3);
            accout.setName("knightzz");
            accout.setMoney(400d);
            accountService.update(accout);
        }
    
        public void testDelete() {
        }
    }
    

2. Spring transaction

2.1 Spring transaction control mode

  • Spring's transaction control can be divided into programmatic transaction control and declarative transaction control.

2.1.1 programmatic transactions

  • Developers directly couple the transaction code and business code, which is not needed in actual development

2.1.2 declarative transactions

  • Developers use configuration to realize transaction control, decouple business code and transaction code, and use AOP idea.

2.2 programmable transaction control object

2.2.1 different Dao layer implementation objects

  • PlatformTransactionManager is an interface type, and different Dao layer technologies have different implementation classes.
  • When Dao layer technology is JDBC template or mybatis: DataSourceTransactionManager
  • When Dao layer technology is hibernate: hibernate transaction manager
  • When Dao layer technology is JPA: JPA transaction manager

2.2.2 PlatformTransactionManager

  • The PlatformTransactionManager interface is the transaction manager of spring,

  • It provides our common methods of operating transactions

  • common method

2.2.3 TransactionDefinition

  • The TransactionDefinition interface provides transaction definition information (transaction isolation level, transaction propagation behavior, etc.)

  • common method

2.2.4 transaction isolation level

  • Unreadable, dirty and unreadable

  • Setting the isolation level can solve the problems caused by transaction concurrency, such as dirty reading, non repeatable reading and virtual reading (phantom reading).

  • ISOLATION_DEFAULT uses the database default level

  • ISOLATION_READ_UNCOMMITTED read uncommitted

  • ISOLATION_READ_COMMITTED read committed

  • ISOLATION_REPEATABLE_READ repeatable

  • ISOLATION_SERIALIZABLE serialization

2.2.5 transaction communication behavior

  • Transaction propagation behavior refers to how to control transactions when a business method is called by another business method

  • Read only: it is recommended to set it as read-only when querying

  • Timeout: the default value is - 1. There is no timeout limit. If yes, set in seconds

2.2.6 TransactionStatus

  • The TransactionStatus interface provides the specific running status of a transaction.

  • We can simply understand the relationship between the three: the transaction manager manages the transaction by reading the transaction definition parameters, and then a series of events will occur
    Business status.

2.2.7 code implementation

  • SpringConfig

    @Bean("transactionManager")
    public DataSourceTransactionManager getDataSourceTransactionManager(@Autowired DataSource dataSource){
        return new DataSourceTransactionManager(dataSource);
    }
    
  • Service

     @Resource
        private PlatformTransactionManager transactionManager;
    
        /**
         * Transfer operation
         *
         * @param outUser
         * @param inUser
         * @param money
         */
        @Override
        public void transfer(String outUser, String inUser, Double money) {
                // Create transaction definition object
                DefaultTransactionDefinition def = new DefaultTransactionDefinition();
                // Set whether it is read-only. false supports transactions
                def.setReadOnly(false);
                // Set the transaction isolation level. You can repeatedly read the default level of mysql
                def.setIsolationLevel(TransactionDefinition.ISOLATION_REPEATABLE_READ);
                // Transaction propagation behavior must be set
                def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
                // Configure transaction manager
                TransactionStatus status = transactionManager.getTransaction(def);
                try {
                    // transfer accounts
                    accountDao.out(outUser, money);
                    accountDao.in(inUser, money);
                    // Commit transaction
                    transactionManager.commit(status);
                } catch (Exception e) {
                    e.printStackTrace();
                    // Rollback transaction
                    transactionManager.rollback(status);
                }
        }
    

2.3 declarative transaction control based on XML

2.3.1 development steps

  • Introduce tx namespace
  • Transaction manager notification configuration
  • Transaction manager AOP configuration
  • Test transaction control transfer business code

2.3.2 introducing tx namespace

<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w2.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/s chema/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 http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
    
</beans>

2.3.3 transaction manager notification configuration

<!--Transaction manager--> 
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 
    <property name="dataSource" ref="dataSource"></property> 
</bean> <!--Notification enhancement--> 
<tx:advice id="txAdvice" transaction-manager="transactionManager"> 
    <!--Define the properties of the transaction--> 	
    <tx:attributes> 
    <tx:method name="*"/> 
	</tx:attributes> 
</tx:advice>

2.3.4 transaction manager AOP configuration

<!--aop to configure--> 
<aop:config> <!--Section configuration--> 
    <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.lagou.serivce..*.*(..))"> </aop:advisor> 
</aop:config>

2.3.5 configuration of transaction parameters

<tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" timeout="-1" read-only="false"/>
  • Name: tangent point method name

  • Isolation: isolation level of transaction

  • Propagation: propagation behavior of transactions

  • Timeout: timeout

  • Read only: read only

2.3.6 common configuration of crud transaction

<tx:attributes> 
    <tx:method name="save*" propagation="REQUIRED"/>
    <tx:method name="delete*" propagation="REQUIRED"/> 
    <tx:method name="update*" propagation="REQUIRED"/> 
    <tx:method name="find*" read-only="true"/> 
	<tx:method name="*"/> 
</tx:attributes>

2.4 annotation based declarative transaction control

2.4.1 basic steps

  • Modify the service layer and add transaction annotation
  • Modify the spring core configuration file and enable transaction annotation support

2.4.2 enable transaction configuration

  • Springconfig: @ enabletransactionmanagement start transaction

    @Configuration
    @ComponentScan("cn.knightzz")
    @EnableAspectJAutoProxy
    @EnableTransactionManagement
    @Import(DataSourceConfig.class)
    public class SpringConfig {
    

2.4.3 adding notes to service

  • Note: the code of transaction annotation should not be wrapped with try catch, otherwise the exception cannot be caught and rolled back

        @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ, timeout = -1, readOnly = false)
        @Override
        public void transfer(String outUser, String inUser, Double money) {
            accountDao.out(outUser, money);
            int i = 1 / 0;
            accountDao.in(inUser, money);
        }
    

Keywords: Java Spring Transaction

Added by salomo on Wed, 02 Feb 2022 10:35:43 +0200