No, it came again for the last time -- integrating Mybatis and transaction management ("easiest to understand Spring learning")

Keywords: Java Mybatis Spring SQL SSM

🏇 wood wood have word say : \textcolor{Orange} {Mu has something to say:} Mumu said:
🍣 this day yes s p r i n g of most after one individual word topic , sound bright type matter Affairs with and whole close M y b a t i s \textcolor{green} {today is the last topic of spring, declarative transactions and integrating Mybatis} Today is the last topic of spring, declarative transactions and integrating Mybatis 🍣
🍣 I Guys of most end order mark yes take M y b a t i s , S p r i n g , S p r i n g M V C whole close stay one block \textcolor{green} {our ultimate goal is to integrate Mybatis, Spring and Spring MVC} Our ultimate goal is to integrate Mybatis, Spring and Spring MVC together 🍣
🍣 lower one rank paragraph of learn Learn Just yes S p r i n g M V C \textcolor{green} {the next stage of learning is spring MVC} The next stage of learning is spring MVC 🍣
🙏 Bo main also stay learn Learn rank paragraph , as if hair present ask topic , please Tell know , wrong often sense thank \textcolor{Orange} {blogger is also in the learning stage. If you find any problems, please let me know. Thank you very much} Bloggers are also in the learning stage. If you find any problems, please let us know. Thank you very much 💗

📬 to stage PUSH Recommend : \textcolor{red} {previous recommendations:} Previous recommendations:
🐳 Click to send you to "a brief understanding of the theoretical derivation of Spring and IOC"
🐳 Click to send you to IOC and DI in Spring
🐳 Click to send you to AOP and proxy patterns in Spring
🐳 Click to send you to Spring's automatic assembly and annotation development

12, Integrate Mybatis

step Suddenly : \textcolor{red} {step:} Steps:

  1. Import related jar packages

    • junit
    • mybatis
    • mysql database
    • spring related
    • aop weaving
    • mybatis-spring[new]

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.26</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.7</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.3.11</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.3.11</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.7</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.6</version>
        </dependency>
    </dependencies>
    <build>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
            </resource>
        </resources>
    </build>
    
  2. Write configuration file

  3. test

1. Recall mybatis

  • Writing entity classes

    package com.hxl.pojo;
    
    import lombok.Data;
    
    @Data
    public class User {
        private int id;
        private String name;
        private String pwd;
    }
    
  • Write core configuration file

    <?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">
    <!--Core profile-->
    <configuration>
        <typeAliases>
            <package name="com.hxl.pojo"/>
        </typeAliases>
    
        <environments default="development">
            <environment id="development">
                <!--transaction management-->
                <transactionManager type="JDBC"/>
                <dataSource type="POOLED">
                    <property name="driver" value="com.mysql.jdbc.Driver"/>
                    <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
                    <property name="username" value="root"/>
                    <property name="password" value="123456"/>
                </dataSource>
            </environment>
        </environments>
        <!--every last Mapper.xml All need to be in Mybatis Register in core profile-->
        <mappers>
            <!--use class If necessary mapper The two names are the same and under the same package-->
            <mapper resource="com/hxl/mapper/UserMapper.xml"/>
        </mappers>
    </configuration>
    
  • Write interface

    package com.hxl.mapper;
    
    import com.hxl.pojo.User;
    
    import java.util.List;
    
    public interface UserMapper {
        public List<User> selectUser();
    }
    
  • Write Mapper.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.hxl.mapper.UserMapper">
    
        <select id="selectUser" resultType="user">
            select * from user
        </select>
    
    </mapper>
    

    Don't write the value of namspace wrong here, otherwise a binding error will occur

    o r g . a p a c h e . i b a t i s . b i n d i n g . B i n d i n g E x c e p t i o n : T y p e i n t e r f a c e c o m . h x l . m a p p e r . U s e r M a p p e r i s n o t k n o w n t o t h e M a p p e r R e g i s t r y . \textcolor{red}{org.apache.ibatis.binding.BindingException: Type interface com.hxl.mapper.UserMapper is not known to the MapperRegistry.} org.apache.ibatis.binding.BindingException:Typeinterfacecom.hxl.mapper.UserMapperisnotknowntotheMapperRegistry.​

    Moreover, we can check whether the User Mapper.xml in the target determines our configuration

  • test

    import com.hxl.mapper.UserMapper;
    import com.hxl.pojo.User;
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    import org.junit.Test;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.List;
    
    public class MyTest {
        @Test
        public void test() throws IOException {
            //Tool class before
            String resources = "mybatis-config.xml";
            InputStream resourceAsStream = Resources.getResourceAsStream(resources);
            SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
            SqlSession sqlSession = sessionFactory.openSession(true);
    
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            List<User> users = mapper.selectUser();
            for (User user : users) {
                System.out.println(user);
            }
        }
    }
    

2. Mybatis-Spring

[official website] 🐳 Click to send you to the official website

  • Write data source configuration
  • sqlSessionFactory
  • sqlSessionTemplate

spring-dao.xml for the above three

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

    <!--DataSource:use Spring Data source replacement for Mybatis Configuration of:c3p0  dbcp  druid
    Use here Spring Provided JDBC.
    After we use it here, we can mybatis-config.xml Removed from
    -->
    <bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>
    <!--sqlSessionFactory-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--Bind the data source written above-->
        <property name="dataSource" ref="datasource"/>
        <!--binding mybatis configuration file-->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <!--In this case, the original registration mapper You don't need it-->
        <property name="mapperLocations" value="classpath:com/hxl/mapper/*.xml"/>
    </bean>

    <!--SqlSessionTemplate That's what we use sqlSession-->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <!--Only constructor injection can be used sqlSessionFactory,Because it doesn't set method-->
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>

    <!--Inject into spring in-->
    <bean id="userMapper" class="com.hxl.mapper.UserMapperImpl">
        <property name="sqlSession" ref="sqlSession"/>
    </bean>
</beans>
  • You need to add an implementation class to the interface
package com.hxl.mapper;

import com.hxl.pojo.User;
import org.mybatis.spring.SqlSessionTemplate;

import java.util.List;

public class UserMapperImpl implements UserMapper{
    //All our operations were originally executed with sqlSession, but now we use SqlSessionTemplate
    private SqlSessionTemplate sqlSession;

    public void setSqlSession(SqlSessionTemplate sqlSession) {
        this.sqlSession = sqlSession;
    }

    public List<User> selectUser() {
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        return mapper.selectUser();
    }
}
  • Inject the implementation class written by yourself into 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: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
        https://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">

    <import resource="spring-dao.xml"/>

    <!--Inject into spring in-->
    <bean id="userMapper" class="com.hxl.mapper.UserMapperImpl">
        <property name="sqlSession" ref="sqlSession"/>
    </bean>
</beans>
  • test
@Test
public void test2(){
    ApplicationContext context = new ClassPathXmlApplicationContext("spring-dao.xml");
    UserMapper userMapper = context.getBean(UserMapper.class);
    for (User user : userMapper.selectUser()) {
        System.out.println(user);
    }
}

The first two species square type : straight meet Follow Accept one individual class real present \textcolor{orange} {the second way: directly inherit a class implementation} The second way: directly inherit a class implementation

package com.hxl.mapper;

import com.hxl.pojo.User;
import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.support.SqlSessionDaoSupport;

import java.util.List;

public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper{
    public List<User> selectUser() {
        SqlSession sqlSession = getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        return mapper.selectUser();
    }
}

Added in spring Dao and applicationContext

<!--Corresponding second method-->
<bean id="userMapper2" class="com.hxl.mapper.UserMapperImpl2">
    <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>

Finally, let's test:

@Test
public void test2(){
    ApplicationContext context = new ClassPathXmlApplicationContext("spring-dao.xml");
    UserMapper userMapper = context.getBean("userMapper2",UserMapper.class);
    for (User user : userMapper.selectUser()) {
        System.out.println(user);
    }
}

3. Steps

how Do you go whole close , can with ginseng Test one lower \textcolor{green} {how to integrate, you can refer to} How to integrate, you can refer to 👍

  1. pom.xml import package
  2. Entity class
  3. Interface
  4. mybatis-config.xml

Integrate mybatis

  1. spring-dao.xml
  2. UserMapper.xml

An implementation class to use

  1. UserMapperImpl
  2. applicationContext.xml

Finally, let's have a test

13, Declarative transaction

1. Retrospective services

  • Treat a group of businesses as a business. Either all succeed or all fail
  • Transaction is very important in project development, which involves the consistency of data
  • Ensure integrity and consistency

ACID principle of transaction:

  • Atomicity
  • uniformity
  • Isolation
    • Multiple services may operate the same resource at the same time to prevent data corruption
  • persistence
    • Once the transaction is committed, no matter what happens to the system, the result will not be affected and will be written to the memory persistently

2. A case

Let's take down the previous case

In order to prevent errors, the code and steps are adjusted here:

  1. pom.xml import package

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <parent>
            <artifactId>Spring-Study</artifactId>
            <groupId>com.hxl</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>spring-11-transaction</artifactId>
    
        <dependencies>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.12</version>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>8.0.26</version>
            </dependency>
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis</artifactId>
                <version>3.5.7</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-webmvc</artifactId>
                <version>5.3.11</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-jdbc</artifactId>
                <version>5.3.11</version>
            </dependency>
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjweaver</artifactId>
                <version>1.9.7</version>
            </dependency>
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis-spring</artifactId>
                <version>2.0.6</version>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.20</version>
            </dependency>
        </dependencies>
        <build>
            <resources>
                <resource>
                    <directory>src/main/resources</directory>
                    <includes>
                        <include>**/*.properties</include>
                        <include>**/*.xml</include>
                    </includes>
                    <filtering>true</filtering>
                </resource>
                <resource>
                    <directory>src/main/java</directory>
                    <includes>
                        <include>**/*.properties</include>
                        <include>**/*.xml</include>
                    </includes>
                </resource>
            </resources>
        </build>
    </project>
    
  2. Entity class

    package com.hxl.pojo;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
        private int id;
        private String name;
        private String pwd;
    }
    
  3. Interface

    package com.hxl.mapper;
    
    import com.hxl.pojo.User;
    
    import java.util.List;
    
    public interface UserMapper {
        public List<User> selectUser();
        //Add a user
        public int addUser(User user);
        //Delete a user
        public int deleteUser(int id);
    }
    
  4. mybatis-config.xml

    <?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">
    <!--Core profile-->
    <configuration>
        <!--Alias management-->
        <typeAliases>
            <package name="com.hxl.pojo"/>
        </typeAliases>
    
        <!--set up-->
        <!--For example, log on-->
    
        <!--<environments default="development">
            <environment id="development">
                &lt;!&ndash;transaction management&ndash;&gt;
                <transactionManager type="JDBC"/>
                <dataSource type="POOLED">
                    <property name="driver" value="com.mysql.jdbc.Driver"/>
                    <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
                    <property name="username" value="root"/>
                    <property name="password" value="123456"/>
                </dataSource>
            </environment>
        </environments>-->
    
    
        <!--every last Mapper.xml All need to be in Mybatis Register in core profile-->
    <!--    <mappers>
            &lt;!&ndash;use class If necessary mapper The two names are the same and under the same package&ndash;&gt;
            <mapper resource="com/hxl/mapper/UserMapper.xml"/>
        </mappers>-->
    </configuration>
    
  5. spring-dao.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"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context
            https://www.springframework.org/schema/context/spring-context.xsd
            http://www.springframework.org/schema/aop
            https://www.springframework.org/schema/aop/spring-aop.xsd">
    
        <!--DataSource:use Spring Data source replacement for Mybatis Configuration of:c3p0  dbcp  druid
        Use here Spring Provided JDBC.
        After we use it here, we can mybatis-config.xml Removed from
        -->
        <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
            <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
            <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
            <property name="username" value="root"/>
            <property name="password" value="123456"/>
        </bean>
        <!--sqlSessionFactory-->
        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
            <!--Bind the data source written above-->
            <property name="dataSource" ref="dataSource"/>
            <!--binding mybatis configuration file-->
            <property name="configLocation" value="classpath:mybatis-config.xml"/>
            <!--In this case, the original registration mapper You don't need it-->
            <property name="mapperLocations" value="classpath:com/hxl/mapper/*.xml"/>
        </bean>
    
        <!--SqlSessionTemplate That's what we use sqlSession-->
        <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
            <!--Only constructor injection can be used sqlSessionFactory,Because it doesn't set method-->
            <constructor-arg index="0" ref="sqlSessionFactory"/>
        </bean>
    </beans>
    
  6. UserMapper.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.hxl.mapper.UserMapper">
    
        <!--resultType:It is mainly used to extract data from the database-->
        <select id="selectUser" resultType="user">
            select * from user
        </select>
    
        <insert id="addUser" parameterType="user">
            insert into user(id,name,pwd) values (#{id},#{name},#{pwd})
        </insert>
    
        <delete id="deleteUser" parameterType="int">
            deletes from user where id=#{id}
        </delete>
    </mapper>
    
  7. UserMapperImpl

    package com.hxl.mapper;
    
    import com.hxl.pojo.User;
    import org.mybatis.spring.SqlSessionTemplate;
    import org.mybatis.spring.support.SqlSessionDaoSupport;
    
    import java.util.List;
    
    public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper{
    
        public List<User> selectUser() {
    
            User user = new User(5, "Old five", "123456");
    
            UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
            mapper.addUser(user);
            mapper.deleteUser(5);
    
            return mapper.selectUser();
        }
    
        public int addUser(User user) {
            return getSqlSession().getMapper(UserMapper.class).addUser(user);
        }
    
        public int deleteUser(int id) {
            return getSqlSession().getMapper(UserMapper.class).deleteUser(id);
        }
    }
    
  8. applicationContext.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"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context
            https://www.springframework.org/schema/context/spring-context.xsd
            http://www.springframework.org/schema/aop
            https://www.springframework.org/schema/aop/spring-aop.xsd">
    
        <import resource="spring-dao.xml"/>
    
        <!--Inject into spring in-->
        <bean id="userMapper" class="com.hxl.mapper.UserMapperImpl">
            <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
        </bean>
    </beans>
    
  9. test

    import com.hxl.mapper.UserMapper;
    import com.hxl.pojo.User;
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class MyTest {
        @Test
        public void test(){
            ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
            UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
            for (User user : userMapper.selectUser()) {
                System.out.println(user);
            }
        }
    }
    

Here is to reproduce the error of the database: the delete statement we wrote is wrong. We found that the added data was added to the database. This is wrong, because our deletion statement failed and the result was inserted, which is not in line with our principle. A C I D primary be \textcolor{red}{ACID principle} ACID principle

3. Transaction management in spring

  • Declarative transaction: AOP
  • Programming transaction: it is necessary to manage the transaction in the code

The above problem can be realized by adding the following code to spring Dao. delete reports an error, and add will not be added

<!--combination aop Realize the weaving of transactions: you need to find an entry point or aspect-->
<!--1.Configure transaction Notifications:-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <!--Configure transactions for methods;
        To configure the propagation properties of a transaction: new propagation="REQUIRED"The default is it. You can not write it
        -->
    <tx:attributes>
        <tx:method name="add" propagation="REQUIRED"/>
        <tx:method name="delete" propagation="REQUIRED"/>
        <tx:method name="update" propagation="REQUIRED"/>
        <tx:method name="query" read-only="true"/>
        <tx:method name="*" propagation="REQUIRED"/>
    </tx:attributes>
</tx:advice>
<!--2.Configure transaction entry-->
<aop:config>
    <aop:pointcut id="txPointCut" expression="execution(* com.hxl.mapper.*.*(..))"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>

thinking Test : \textcolor{orange} {thinking:} Thinking:

Why transactions are needed?

  • If transactions are not configured, there may be inconsistent data submission
  • If we do not configure declarative transactions in spring, we need to manually configure transactions in the code,
  • Transaction is very important in development, which involves the consistency and integrity of data.

Posted by utexas_pjm on Tue, 23 Nov 2021 21:45:19 -0800