java | MyBatis - configuration, mapping, caching

MyBatis is a persistence layer framework that can customize SQL, stored procedures, and advanced mappings. MyBatis eliminates most of the JDBC code, manually setting parameters and recovering result sets. MyBatis uses simple XML and annotations to configure and Map basic data types, Map interfaces, and POJO s to database records

SqlSessionFactory is the core engine of the MyBatis framework
SqlSessionFactory contains the most basic metadata configuration of MyBatis and provides the maintenance of specific SqlSession instances accessing the database. Generally, SqlSessionFactory builder is used to create a SqlSessionFactory instance

Configure MyBatis

Basic configuration

Configuration xml file
configuration.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>
    <!--Load database mapping properties file-->
    <properties resource="com/conf/dbconf.properties"/>
    <!--Configure data source information-->
    <environments default="bizdb">
        <environment id="bizdb">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="url" value="${jdbc_url}"/>
                <property name="username" value="${jdbc_user}"/>
                <property name="driver" value="${jdbc_driver}"/>
                <property name="password" value="${jdbc_password}"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="com/domin/department-mapper.xml"/>
    </mappers>



</configuration>

Of course, maven is used here to find packages

    <!-- mybatis Core package -->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.2.8</version>
    </dependency>
    <!-- jdbc My bag -->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.32</version>
    </dependency>

There are many bags, so I won't list them one by one
jdbc conf involved:

jdbc_url = jdbc:oracle:thin:@127.0.0.1:1521:system
jdbc_driver = oracle.jdbc.driver.OracleDriver
jdbc_user = system
jdbc_password = ****

Build SqlSessionFactory and obtain SqlSession

package com.util.db;

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 java.io.IOException;
import java.io.Reader;

public class MySqlSessionManager {
    /*Configure the external xml file path of myBatis basic metadata*/
    private static final String CONFIG_FILE = "com/conf/configuration.xml";


    /*Create sqlsession*/
    public static SqlSession getSqlSession(){
        SqlSessionFactory ssf = newSqlSessionFactory();
        SqlSession sqlSession = null;
        sqlSession = ssf.openSession();
        System.out.println("sqlSession example" + sqlSession);
        return sqlSession;
    }

    /*Use the resource component to obtain an input stream based on a file*/
    private static SqlSessionFactory newSqlSessionFactory(){
        SqlSessionFactory ssf = null;
        Reader reader = null;
        try {
            reader = Resources.getResourceAsReader(CONFIG_FILE);
            ssf = new SqlSessionFactoryBuilder().build(reader);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return ssf;
    }
}

Create class
Department.java

package com.domin;

import java.util.Date;

public class Department {
    private String id;
    private String name;
    private String code;
    private Date newDate;
    private String descs;

    public Department() {
    }

    public Department(String id, String name, String code, Date newDate, String descs) {
        this.id = id;
        this.name = name;
        this.code = code;
        this.newDate = newDate;
        this.descs = descs;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public Date getNewDate() {
        return newDate;
    }

    public void setNewDate(Date newDate) {
        this.newDate = newDate;
    }

    public String getDisc() {
        return descs;
    }

    public void setDisc(String disc) {
        this.descs = disc;
    }
}

Create class related mapping file configuration xml
department-mapper.xml
(the name of this file is optional, but it's better to standardize it.)

  <?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="depns">
    <select id="queryDeplist" resultType="com.domin.Department">
        select "id","name","code","newdate","descs" from "department"
    </select>
</mapper>

At the same time, add mapper in configuration.xml

    <mappers>
        <mapper resource="com/domin/department-mapper.xml"/>
    </mappers>

ok, everything is ready. Create a servlet to Kangkang

package com.servlet;

import com.domin.Department;
import com.service.DepartmentService;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

public class testServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        List<Department> list = DepartmentService.queryDeplist();

        for(Department dep:list){
            System.out.println("name:" + dep.getName());
            System.out.println("code:" + dep.getCode());
        }
    }
}

I put a piece of data in the database

Now run tomcat, and the data is sent to the console

Mapping sql with annotations

Annotations are in the interface
IDepartmentMapper,java

package com.dao;

import com.domin.Department;
import org.apache.ibatis.annotations.Select;

import java.util.List;

public interface IDepartmentMapper {
    @Select("select * from \"department\"")
    public List<Department> queryDepList();
}

In configuration.xml, add mapper

    <mappers>
<!--        <mapper resource="com/domin/department-mapper.xml"/>-->
        <mapper class="com.dao.IDepartmentMapper"/>
    </mappers>

Create a method in DepartmentDao.java (there is also a DepartmenetService call, which will not be demonstrated)

    /*Using annotations to implement sql mapping execution*/
    public static List<Department> queryDeplist2ByMapper(){
        SqlSession sqlSession = MySqlSessionManager.getSqlSession();
        return sqlSession.getMapper(IDepartmentMapper.class).queryDepList();
    }

Call in sevlet:

        List<Department> list2 = DepartmentService.queryDeplistByMapper();
        for(Department dep:list2){
            System.out.println("name:" + dep.getName());
            System.out.println("code:" + dep.getCode());
        }

Start tomcat and type the result

Main API life cycle

The main function of SqlSessionFactoryBuilder instance is to create a SqlSessionFactory to survive. Therefore, if a SqlSessionFactory instance is created successfully, the instance can not be discarded. Saving this object for a long time does not make much sense in memory. It is recommended to use it in a method body

After SqlSessionFactory is created, it is always stored in the throughout the Application process. Generally, when multiple data sources are not involved in an Application, there will only be one SqlSessionFactory instance, so its life cycle should be Application. This instance is usually defined as a singleton pattern

SqlSession is the main interface for operating database business. This instance is not thread safe and cannot share this object. Its scope should be in the current request or a method body, and it should not use a static variable of the class to refer to a SqlSession instance, or even an instance variable of the class.
This object must not be referenced in a session scope in the web application. It should be released as the user's HTTP request ends. After using SqlSession to perform database operations, close SqlSession in time

Mapper instance must be created by a SqlSession object, and when using mapper instance to implement database operation, it must also ensure that the SqlSession that created it is open
Therefore, the life cycle of Mapper is usually the same as that of SqlSession. After a SqlSession is closed or destroyed, Mapper instances created based on this SqlSession will not be used

Alias typeAliases

In configuration.xml (Mybatis configuration file XML), the aliases of classes are configured by typeAliases and typealias:

    <typeAliases>
        <typeAlias type="com.domin.Department" alias="dept"/>
    </typeAliases>

You can use it in department-mapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="depns">
    <select id="queryDeplist" resultType="dept">
        select "id","name","code","newdate","descs" from "department"
    </select>
</mapper>

Here, the value of resultType is dept, and an alias is used

Mybatis predefined type alias:
The basic data alias used is prefixed and underlined (for example, the alias of int type is _int)
The wrapper class behavior of all base types starts with lowercase (for example, the alias of integer type is integer)

    <select id="queryCountNum" resultType="integer">
        select count(id) from department
    </select>

...dao.java

    /*Calculate the number of departments*/
    public static List<Integer> queryCountNum(){
        SqlSession sqlSession = MySqlSessionManager.getSqlSession();
        return sqlSession.selectList("depns.queryCountNum");
    }

sevlet

System.out.println("Total departments:" + DepartmentDao.queryCountNum().get(0));

Results slightly

environments configuration

environments is used to configure data source information. It must have at least one data source (environment child element) configuration

The transactionManager child element defines the type of database transactions that myBatis handles
myBatis database transactions support two types:
JDBC: this type uses the commit and rollback function. It uses the connected data source to manage the scope of the transaction

MANAGED: this type does nothing and never commits, rolls back, and closes connections. Let other containers or code implementations manage the entire life cycle of transactions (such as spring or Java EE containers)

dataSoure child element
Used to configure JDBC database attribute information in a certain environment. MyBatis provides three types of data sources
UNPOOLED: this type simply opens and closes a connection every time it requests. It does not use any connection pool technology. Its performance is poor. It is not recommended
POOLED: this type caches JDBC connection objects to avoid the verification time required to connect and generate connection instances every time (the advantage of using connection pool). For concurrent WEB applications, it is recommended to use data sources in this way
JNDI: this type uses the data source configured on the matching application server to find the data source object on a server through the java named directory interface


mappers

The total of the mappers element tells the Mybatis framework how to load the SQLMap mapping file or identify the annotated interface during initialization. It is written above and omitted here

SQL mapping

select (with parameters)

It has been demonstrated before. Here is a demonstration with parameters
sql statements can be surrounded by: <! [CDATA []] > to tell the system to summarize the statements and treat any special characters as non semantic
Properties of select:

The following is a description of querying a customer:
customer.java

package com.domin;

public class Customer {
    private String name;
    private int age;
    private String sex;

//The constructor and get and set methods are omitted below

customer-mapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cus">
    <select id="queryCustomer" parameterType="int" resultType="com.domin.Customer">
        <![CDATA[select "name","age","sex" from "customer" where "age" > #{age}]]>
    </select>
</mapper>

Note that the mapper's namespace should be written, otherwise an error will be reported
In addition, the <! [CDATA []] > in < Select > is grayed out in csdn. In fact, it is not a comment!
#{} represents a variable. The age in it has no meaning and is used to occupy bits
customDao.java, write the query method

package com.dao;

import com.domin.Customer;
import com.util.db.MySqlSessionManager;
import org.apache.ibatis.session.SqlSession;
import java.util.List;

public class CustomerDao {
    public static List<Customer> queryCustomer(int age){
        List<Customer> list = null;
        SqlSession sqlSession = MySqlSessionManager.getSqlSession();
        list = sqlSession.selectList("cus.queryCustomer",age);
        return list;
    }
}

The age parameter is passed in here
In servlet

        List<Customer> list3 = CustomerDao.queryCustomer(18);
        for(Customer c:list3){
            System.out.println(c.getName() + "  " + c.getAge() + "  " + c.getSex());
        }

Oh, and add < mapper > in configuration.xml

        <mapper resource="com/domin/customer-mapper.xml"/>

customer in my database:

result:

selectOne and return set

selectOne: only one is returned, not a list like selectList

(Continued)
customer.xml

    <select id="queryCustomerByName" parameterType="String" resultType="map">
        <![CDATA[select name,age,sex from customer where name = #{name}]]>
    </select>

dao.java

public static Map<String,Object> queryCustomerByName(String name){
    return MySqlSessionManager.getSqlSession().selectOne("cus.queryCustomerByName",name);
}

servlet

        Map<String,Object> map = CustomerDao.queryCustomerByName("liang");
        System.out.println(map.get("NAME").toString());
        System.out.println(map.get("AGE").toString());
        System.out.println(map.get("SEX").toString());

Note that the key here should be capitalized, otherwise an error will be reported
result:

insert and update

< Insert > < update > general attributes
id *: SQL Sports Bureau reference unique id, required attribute
Flush cache: whether the cache data is refreshed during update (true, false)
useGeneratedKeys: use the self generated unique identifier (primary key) and use the domain to automatically grow the primary key table
keyProperty: specifies which property is automatically generated to identify the feedback to the object when the object is saved
keyColumn: Specifies the name of the primary key column that identifies the underlying table of the trace automatically generated when the object is saved
databaseId: specifies which data source to operate on. It corresponds to the global configuration < databaseidprovide > and is used to switch databases

insert usage demonstration
Add the insert method in department-mapper.xml and pass in a map

    <insert id="addCustomer" parameterType="map" keyColumn="ID" keyProperty="id"
    flushCache="true" statementType="PREPARED">
        <![CDATA[insert into department(id,name,code,newdate,descs)
            values(#{id},#{name},#{code},#{newdate},#{descs})]]>
    </insert>

In DepartmentDao.java:

    public static int addCustomer(Map<String,Object> map){
        SqlSession sqlSession = MySqlSessionManager.getSqlSession();
        int r = sqlSession.insert("depns.addCustomer",map);
        sqlSession.commit();
        sqlSession.close();
        return r;
    }

Note that the commit method should be added, otherwise the insert information cannot be found
Add a map to the servlet and pass it as a parameter into addCustomer

Map<String,Object> map = new HashMap<String,Object>();
        map.put("id","1");
        map.put("name","Chen Zheng");
        map.put("code","111");
        map.put("newdate",new Date());
        map.put("descs","remarks");
        int r = DepartmentDao.addCustomer(map);
        System.out.println("Insert:" + r);

The result is 1, indicating success:
Go to the software and find it successful

update usage demo
department-mapper.xml

    <update id="updateDepartment" parameterType="map" keyColumn="ID" keyProperty="id"
            statementType="PREPARED">
        update department set name=#{name} where id = #{id}
    </update>

Dao.java

public static int updateDepartment(Map<String,Object> map){
    SqlSession sqlSession = MySqlSessionManager.getSqlSession();
    int result = sqlSession.update("depns.updateDepartment",map);
    sqlSession.commit();
    sqlSession.close();
    return result;
}

servlet

        Map<String,Object> map = new HashMap<String, Object>();
        map.put("id","33");
        map.put("name","Fishing Department");
        DepartmentDao.updateDepartment(map);

Results (compared with the insert demonstration, the fishing department is changed to the fishing Department):

delete

Direct demonstration;
department-mapper.xml

    <delete id="deleteDepartmentById" flushCache="true"
            statementType="PREPARED" parameterType="string">
        delete from department where id = #{id}
    </delete>

...Dao.java

    public static int deleteDepartmentById(String id){
        SqlSession sqlSession = MySqlSessionManager.getSqlSession();
        int result = sqlSession.delete("depns.deleteDepartmentById",id);
        sqlSession.commit();
        sqlSession.close();
        return result;
    }

servlet
Delete all rows with id 1

        DepartmentDao.deleteDepartmentById("1");

result:

sql reuse


Direct example:
sql tags to replace these strings

    <sql id="depCommon">id,name,code,newdate,descs</sql>

Put this label in < mapper >
Then modify the < Select > of the query

    <select id="queryDeplist" resultType="dept" fetchSize="2">
            select <include refid="depCommon"/> from department
    </select>

If the effect is the same, the servlet code will not be pasted
The select statement here cannot be wrapped in CDATA, otherwise < include > will be useless and will report errors. The solution is unknown, so CDATA will not be used directly.

myBaits cache

Create cache:

Data caching can increase the efficiency of data access and operation. myBatis provides setting sql caching policies and referencing caching policies in sql mapping;
myBatis uses cache elements to set cache policies in sql maps and ref cache to reference cache policies.

Cache policy in MyBatis
LRU least recently used method (default): remove objects that have not been used in the last long cycle
FIFO first in first out: move out the earlier objects in the queue
SOFT soft reference: Based on SOFT reference rules, garbage collection mechanism is used to remove objects
WEAK weak reference: Based on WEAK reference rules, garbage collection mechanism is used to forcibly remove objects

The cache ref element implements and applies the cache policy referenced from a mapper to the current mapper

myBatis caching mechanism


L2 cache usage configuration

Globalcatch.xml (configure global and custom cache policies)

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="global-catche">
    <!--to configure myBatis Global L2 cache-->
    <cache eviction="LRU" readOnly="true" flushInterval="60000" size="500"/>

</mapper>

Write source in mappers in configuration.xml

    <mappers>
        <mapper resource="com/domin/department-mapper.xml"/>
        <mapper class="com.dao.IDepartmentMapper"/>
        <mapper resource="com/domin/customer-mapper.xml"/>
        <mapper resource="com/conf/globalCatche.xml"/>
    </mappers>

Call in department-mapper.xml

<cache-ref namespace="global-catche"/>

Defects of L2 cache
Operations on a table are no longer performed in its independent namespace (single table operations)
Multiple table operations are severely restricted, resulting in incorrect access to cached data
The cache object type must be a serialized implementation
More unknown errors may occur when the amount of data is large

Tags: Java Database Cache

Posted on Sun, 24 Oct 2021 18:23:27 -0400 by Simplicity