Learning route of SSM mode - [introduction notes of mybatis]

Mybatis is a persistence layer framework. In detail, it is a version persistence framework. It is configured through simple xml or annotations, so that the operation of the database is not so cumbersome;

What is mybatis

mybatis is a retrograde mapping framework, which is used to solve some problems encountered in database operation;

As the number of tables in the Hibernate framework increases, it is not as efficient as the number of tables in the Hibernate framework that can be used to perform dynamic queries. However, the number of tables in the Hibernate framework is also lower than that in the hibernis framework, and the number of tables that can be used to perform dynamic queries is also lower, Therefore, hibernate is suitable for projects that are not too complex and have low performance requirements;

Simple case -- database CURD

mybatis does not rely on spring, but they are usually used together. In actual development, we often encounter the query function. If it is developed through jdbc, the amount of code will be large. At the same time, if you want to modify the query, you need to modify the code of the whole program, which is very inconvenient;

Query user
In the actual development, the query operation usually involves the accurate query of single data and the fuzzy query of multiple data.

Step 1 ------ > > > create a maven project

Introduce corresponding dependencies -
lombok
mybatis
junit
mysql-connector
log4j

The following is the dependent code, which can be taken away directly

<dependencies>
<!--    Automatic resource management getters,setters,equals,hashCode and toString-->
    <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.22</version>
        <scope>provided</scope>
    </dependency>

    <!--test Junit-->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13.2</version>
        <scope>compile</scope>
    </dependency>

    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.7</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.27</version>
    </dependency>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>
</dependencies>

Then began to write code to achieve the desired function;
Take the background database of the store here as an example

You also need to prepare a data table - > > >

DROP TABLE IF EXISTS `bookstore`;

CREATE TABLE `bookstore` (
  `BookId` int NOT NULL,
  `BookName` varchar(255) DEFAULT NULL,
  `BookPublish` varchar(255) DEFAULT NULL,
  `BookPrice` double(10,2) DEFAULT NULL,
  `BookKind` varchar(16) DEFAULT NULL,
  `BookCount` int DEFAULT NULL,
  PRIMARY KEY (`BookId`),
  KEY `name_index` (`BookName`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;



insert  into `bookstore`(`BookId`,`BookName`,`BookPublish`,`BookPrice`,`BookKind`,`BookCount`) values 
(1001,'java introduction','Tsinghua Publishing House',56.80,'computer',70),
(1002,'python thorough','Machinery Industry Press',78.60,'computer',130),
(1003,'front end html','Tsinghua Publishing House',88.80,'computer',100),
(1004,'feidu ','Zhangjiang Publishing House',25.70,'Literary classics',100),
(1005,'Revealing Original Shape in Officialdom','Qingdao Publishing House',23.80,'Literary classics',100),
(1006,'The Dream of Red Mansion','Qingdao Publishing House',36.80,'Literary classics',100),
(1007,'Postpartum care of sows','Machinery Industry Press',27.80,'Practical technology',100),
(1008,'Complete book of vehicle maintenance','Machinery Industry Press',26.80,'Practical technology',100),
(1009,'How to please the rich woman','Happy Publishing House',125.00,'Life skills',100),
(1010,'JVM tuning ','Beijing Science and Technology Press',68.90,'computer',120),
(1011,'GO','Nanjing post and Telecommunications Publishing House',78.90,'computer',120),
(1012,'Android introduction','Electronic Science and Technology Press',88.90,'computer',120),
(1014,'Fruit tree planting','Northwest agriculture and Forestry Press',128.90,'Agriculture',120),
(1015,'joke','Shanghai Publishing House',48.90,'life',120),
(1111,'MQ Message queue','Peking University Press',98.90,'computer',120);

Step 2 --------- > > > write code to realize the function
Write an entity class
It seems that there are a lot of fields in the data table. Don't be afraid. lombok has been introduced to simplify the amount of code;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Book implements Serializable {
    private Integer BookId;
    private String BookName;
    private String BookPublish;
    private Double BookPrice;
    private String BookKind;
    private Integer BookCount;
}

Is it very concise? set/get methods, toString,hashcode, etc. are implemented through lombok annotations instead of using them. If you encounter errors in the process of use, you may not have opened the lombok plug-in to make it take effect automatically

Opening method ----- > > >

Step 3 - > > > create a resource in the resources folder
Mybatis global configuration file mybatis config xml
Before that, you need to configure a jdbc configuration file. Of course, you can also write the database connection elements directly in mybatis config In 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">

<configuration>
    <properties resource="jdbc.properties"/>

    <settings>
        <!--appoint mybatis Log mode,If not specified,Automatic search processing-->
        <setting name="logImpl" value="LOG4J"/>
    </settings>

    <typeAliases>
        <!--The package scans the short path name of the alias class with lowercase initial-->
        <package name="com.gavin.pojo"/>
    </typeAliases>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc_driver}"/>
                <property name="url" value="${jdbc_url}"/>
                <property name="username" value="${jdbc_username}"/>
                <property name="password" value="${jdbc_password}"/>
            </dataSource>
        </environment>
    </environments>

    <!--load mapper Mapping file-->
    <mappers>
        <mapper resource="com.gavin.mapper/BookMapper.xml"/>

    </mappers>
</configuration>

jdbc.properties

jdbc_driver=com.mysql.cj.jdbc.Driver
jdbc_url=jdbc:mysql://127.0.0.1:3306/gavin?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
jdbc_username=gavin
jdbc_password=955945

If you want to print logs, you also need to use log4j or log4j2. This time, take log4j as an example
Create a log configuration file in the resources folder

log4j.properties

log4j.rootLogger=info,stdout,logfile
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.err
log4j.appender.stdout.layout=org.apache.log4j.SimpleLayout
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=d:/gavin.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d{yyyy-MM-dd   HH:mm:ss} %l %F %p %m%n

Finally, write the test class ----- >

Here, we need to understand the workflow of mybatis in order to better write test classes - > > >
First of all, mybatis requires two files ------ mybatis config XML (global configuration file) and mapper XML (mapping file). Of course, the file name does not have to be this
mybatis parses and creates sessions through these two files;
Each session will create a sqlsessionFactory object, and then create a sqlsession object through the factory object. The sqlsession object is used to receive requests, analyze which sql statements to execute, and then pass them to the executor for execution. statementHandler will be used to connect to the database during execution;
This is the basic working principle of mybatis;
Look at the picture - > >

Then start to write the test code, and complete the test writing through the test module;

public class Test1 {
    private  SqlSession sqlSession =null;
    @Before
    public void init(){
        InputStream resource =null;
        //Load Configure File 
        try {
           resource= Resources.getResourceAsStream("mybatis-config.xml");
            SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resource);
            sqlSession= build.openSession(true);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    @Test
    public void test(){

        List<Book> list = sqlSession.selectList("findAll");
        list.stream().forEach(System.out::println);
    }
    @After
    public void testClose(){
        sqlSession.close();
    }
}

Operation results ----- > > >


Sometimes we will encounter some mistakes. Don't worry. Check the log carefully to see what went wrong;

In fact, the principle of adding, deleting, checking and changing questions is the same. We should pay attention to the path of mapper;

OK, le t's start to understand the writing format in each configuration file

Mapper file

Global profile
mybatisconfig.xml

Implement fuzzy query
Just modify the sql statement
However, this writing cannot prevent sql injection,

Check whether there is a suitable method for precompiling. However, no, it can only be spliced through strings,
Like this

Add data

The basic operations remain unchanged, that is, the methods of sql statements and database operations will change;
Note that this time is to insert data, so there is no need to write the return value, because there is no resultType attribute under the insert tag
If the content at the horizontal line of the picture is not removed, an error will be reported,

I don't know why I commented it out clearly, and then found that some things were missing... It's strange that mistakes always appear inadvertently;

Update data


Delete data

In this way, the addition, deletion, query and modification of the database by mybatis is over;
Let's make a little summary ------------ < > >
It can also be seen from the above operations that the operation of mybatis can be roughly divided into six steps;
1. Read the configuration file ----- mybatisconfig XML and mapper xml
2 load the configuration file and create sqlsessionFactory according to the configuration file
3. Create SqlSession according to sqlsessionFactory
4. SqlSession is responsible for contacting the database
5. Close SqlSession

Although on the surface, SqlSession is responsible for connecting to the database, in fact, the underlying layer is implemented by the extractor and statementhandler

Once you are familiar with the workflow, you need to learn more

The core object of MyBatis --------- > > >

SqlSessionFactory

SqlSessionFactory is a compiled memory image of a single database mapping relationship, which is built through the SqlSessionFactoryBuilder object, and the instance of SqlSessionFactory is built by the mybatis global configuration file
therefore
The code can be written down and the global configuration file can be read through the stream

getResourceAsStream method of Resources to read the configuration file, and then build a SqlSessionFactory object through the build of SqlSessionFactory builder;

SqlSessionFactory object is thread safe. Once created, it will exist throughout the execution of the application. If SqlSessionFactory of the same database is created multiple times, the resources of this database will be easily exhausted. Therefore, when building SqlSessionFactory instances, it is recommended to use the single column mode, that is, it is only instantiated once

SqlSession

The JDBC connection is encapsulated in sqlsession, which is a single thread object for the interaction between application and database;

SqlSession instances cannot be shared and are thread unsafe. Therefore, it is best to limit their scope of use to one request or one method. They must not be used in the static field, instance field or any type of management scope of a class. After using the SqlSession object, close it in time. You can usually close it in the finally block.

Common methods in SQL session

  <T> T selectOne(String statement);
//This method returns a generic object that executes the query result of the SQL statement.
  <T> T selectOne(String statement, Object parameter);
//This method returns a generic object that executes the query result of the SQL statement.
  <E> List<E> selectList(String statement, Object parameter);
//This method returns a collection of generic objects that execute SQL statement query results.
  <E> List<E> selectList(String statement, Object parameter);
//This method returns a collection of generic objects that execute SQL statement query results.
  <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds);
  //rowBounds is a parameter object for paging. This method returns a collection of generic objects that execute SQL statement query results.

void select(String statement, Object parameter, ResultHandlerhandler);
//The ResultHandler object is used to process the complex result set returned by the query, which is usually used for multi table queries.

//insert,update,delete,commit and rollback are not displayed here

MyBatis profile

mybatis configuration attribute order

configuration
properties
settings
typeAliases
typeHandlers
objectFactory (object factory)
plugins
environments
Environment (environment variable)
Transaction manager
dataSource
databaseIdProvider (database vendor ID)
mappers

<settings>
  <setting name="cacheEnabled" value="true"/>
  <setting name="lazyLoadingEnabled" value="true"/>
  <setting name="multipleResultSetsEnabled" value="true"/>
  <setting name="useColumnLabel" value="true"/>
  <setting name="useGeneratedKeys" value="false"/>
  <setting name="autoMappingBehavior" value="PARTIAL"/>
  <setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
  <setting name="defaultExecutorType" value="SIMPLE"/>
  <setting name="defaultStatementTimeout" value="25"/>
  <setting name="defaultFetchSize" value="100"/>
  <setting name="safeRowBoundsEnabled" value="false"/>
  <setting name="mapUnderscoreToCamelCase" value="false"/>
  <setting name="localCacheScope" value="SESSION"/>
  <setting name="jdbcTypeForNull" value="OTHER"/>
  <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
</settings>

mapper profile

Error presentation ----- > > >


Let's talk about some small details in the global configuration file in mybatis
For example, an external configuration file JDBC is introduced in the above case development Properties is used for the introduction of variables. In fact, there is another operation, which is very similar to it, but there is no need to configure another file;

Then we can directly introduce a global variable --------- > > into the mybatis configuration file


General developers can or are used to putting the four elements outside the file (jdbc.properties) to reduce the coupling as much as possible;

However, there will be a problem. If both methods are configured, who will follow?

After the actual test, it is found that it follows the external configuration because

myabatis is when reading the configuration
First read the contents in the internal properties,
Then, after reading the information introduced by the external resource, if it has the same name,
The read external resource value will overwrite the internal read value;
Therefore, when temporarily modifying the database connection, it is OK as long as it does not have the same name;

If a property is configured in more than one place, MyBatis will be loaded in the following order:

First read the properties specified in the properties element body. Then, according to the resource in the properties element
Property reads the property file under the classpath, or reads the property file according to the path specified by the url property, and overwrites the previously read property with the same name.
Finally, read the attribute passed as a method parameter and overwrite the previously read attribute with the same name. Therefore, the attribute passed through the method parameter has the highest priority, resource/url
The configuration file specified in the properties takes second place, and the lowest priority is the property specified in the properties element.

At the same time, we can also specify the actual database environment in the code - > >

Set default values

Starting with MyBatis 3.4.2, you can specify a default value for placeholders.

Start the default value in the configuration file. In this case, we can set the default value for a configuration----

  <property name="org.apache.ibatis.parsing.PropertyParser.enable-default-value" value="true"/>

For example, we only set three values in the jdbc configuration file ------ > >

If you use the ":" character in the attribute name (such as db:username), or use the ternary operator of OGNL expression in SQL mapping (such as ${tablename! = null? Tablename: 'global_constants'}), you need to set specific attributes to modify the characters separating attribute name and default value. For example:

<properties resource="org/mybatis/example/config.properties">
  <!-- ... -->
  <property name="org.apache.ibatis.parsing.PropertyParser.default-value-separator" value="?:"/> <!-- Modify the separator of the default value -->
</properties>
<dataSource type="POOLED">
  <!-- ... -->
  <property name="username" value="${db:username?:ut_user}"/>
</dataSource>

#The difference between {} and ${}

When compiling ssql statements, we often use some parameters. When compiling, we are used to precompiling in traditional jdbc operations;

If precompiling is not used, sql injection is likely to occur, so the difference between # {} and ${} is actually the difference between precompiled and non precompiled. Here is a case-----

Set auto increment ----- >


It can be configured separately or in global configuration;

Keywords: Java Database Hibernate Mybatis

Added by mattl on Sun, 06 Feb 2022 04:42:35 +0200