1 Core concepts of myBatis
1.1 Basic Concepts
MyBatis is an excellent persistence layer framework that supports customized SQL, stored procedures, and advanced mapping. MyBatis avoids almost all of the JDBC code and manual setting of parameters and fetching result sets. MyBatis can use simple XML or annotations to configure and map native types, interfaces, and Java’s Plain Old Java Objects (POJOs) to records in the database.
###1.2 Scope and lifecycle of core objects
A simple example:
- UserMapper.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="com.niuh.mybatis.dao.UserMapper">
<select id="selectUser" resultType="com.niuh.mybatis.dao.User">
select * from User where id = #{id}
</select>
</mapper>
Copy the code
- 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">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="JDBC: mysql: / / 192.168.0.147 niuhDB"/>
<property name="username" value="root"/>
<property name="password" value="123456"/> </dataSource> </environment> </environments> <mappers> <! --<mapper resource="com/niuh/mybatis/dao/xml/UserMapper.xml"/>-->
<mapper class="com.niuh.mybatis.dao.UserMapper"></mapper>
</mappers>
</configuration>
Copy the code
Example:
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();
User result = session.selectOne("com.niuh.mybatis.dao.UserMapper.selectUser", 1);
System.out.println(result.toString());
Copy the code
- SqlSessionFactoryBuilder
The session factory is used to build a session factory based on the config. XML environment and props, and can be discarded after construction.
- SqlSessionFactory
Factories used to generate sessions are used for the entire duration of the application, and there is generally no need to construct multiple factory objects
- SqlSession
Acting on a single session, such as during a WEB request, cannot be used as an object property, nor can it be shared across multiple threads because it is thread-unsafe.
1.3 Interface programming
MyBatis introduces the interface mechanism and binds the interface to the namespace name of mapper. XML. MyBatis can dynamically build instances of the interface according to ASM tools.
Session. GetMapper (Class type) is used to obtain the mapper instance, which is usually applied to the method domain.
2 Global configuration
2.1 attributes
The properties element can load properties from an external properties file through a Resource or URL, or set property properties directly. Reference substitution can then be done in XML with ${attribute name}.
<properties resource="app.properties" url="">
<property name="jdbc.driver" value="com.oracle.jdbc.Driver"/>
</properties>
Copy the code
Resource = app.properties loaded from the class path url=[file:///G:/git/niuh-mybatis/src/main/resources/app.properties](file:///G:/git/tuling-mybatis/src/main/resources/app .properties) based on url loading
Way to reference attributes:{jdbc.user:root}
2.2 Environment Configuration
A project often needs to be deployed in different environments, such as development environment, test environment, rehearsal environment and production environment. The corresponding parameters of each environment are different. The properties of different environments can be set by environment in myBatis.
<environments default="${default.environment}">
<environment id="test"> <! --type=JDBC|MANAGED--> <transactionManagertype="JDBC"></transactionManager> <! --type=UNPOOLED|POOLED|JNDI-->
<dataSource type="UNPOOLED">
<property name="driver" value="${jdbc.driver}"/>
</dataSource>
</environment>
<environment id="dev">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
</dataSource>
</environment>
</environments>
Copy the code
Through the SqlSessionFactoryBuilder is build (environment) to specify which set environment initialization.
2.3 set up
Set the global parameters of MyBatis and agree the global behavior of MyBatis
<settings> <! <setting name="cacheEnabled" value="true"/ > <! --> <setting name="mapUnderscoreToCamelCase" value="true"/>
<settings>
Copy the code
Example Hump naming on and off: Try turning the mapUnderscoreToCamelCase property on or off to observe Account data queries.
2.4 the alias
In myBatis, Java types are often used, such as javaType in parameterType parameter reference in SQL block javaType result set mapping, which should use Java full path name, can be passed
<typeAliases>
<typeAlias type="com.niuh.mybatis.dao.Account" alias="account"/>
<package name="com.niuh.mybatis.dao" />
</typeAliases>
Copy the code
Tip: Do not set this parameter. Because the commonly used class mybatis has built-in aliases, and custom class Settings are not easy to find, affect reading.
2.5 Type processors
One of the most important tasks of the persistence layer framework is to deal with the mapping of data, converting Java types to JDBC-type parameters, and converting JDBC-type result sets to Java types. In MyBatis, it is implemented through the TypeHandler interface.
As you can see, typeHandler is just two things that set parameters and get results. You can set up custom processors
<typeHandlers>
<typeHandler handler="org.mybatis.example.ExampleTypeHandler" />
</typeHandlers>
Copy the code
The scope of processing can be specified in two ways
- javaType=”long”, jdbcType=”Date”
- @mappedjdbctypes (JDBC type) @mappedtypes Java types
Example: Convert a timestamp of type long to a date type add an arithmetic definition handler class:
@MappedJdbcTypes(JdbcType.TIMESTAMP) @MappedTypes(Long.class) public class LongTimeHandler extends BaseTypeHandler<Long> { @Override public voidsetNonNullParameter(PreparedStatement ps, int i, Long parameter, JdbcType jdbcType) throws SQLException {
ps.setDate(i, new Date(parameter));
}
@Override
public Long getNullableResult(ResultSet rs, String columnName) throws SQLException {
return rs.getDate(columnName).getTime();
}
@Override
public Long getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return rs.getDate(columnIndex).getTime();
}
@Override
public Long getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
returncs.getDate(columnIndex).getTime(); }}Copy the code
Specify typeHandler in a resultMap:
<resultMap id="account2" type="com.niuh.mybatis.dao.Account">
<result property="createTimestamp" column="createTimestamp" typeHandler="com.niuh.mybatis.dao.LongTimeHandler"/>
</resultMap>
<select id="selectById2" resultMap="account2">
select a.*,a.createTime as createTimestamp from account a where id = #{id}
</select>
Copy the code
2.6 Mappers
<mappers>
<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
<mapper url="http://www.xxx.com/xml/BlogMapper.xml"/>
<mapper class="org.mybatis.builder.BlogMapper"/>
<package name="org.mybatis.builder"/>
</mappers>
Copy the code
Loading mode:
- Resource loads XML files based on the classPath
- Url: Loads XML files based on resource location
- Class: load based on interface
- Package: Scans all classes in the package and loads them
- Rules of engagement:
- The namespace in the Mapper must correspond to the interface name.
- The.xml file must be in the same level of directory as the interface when loaded through a class or package.
3 mapper file
3.1 SQL Statement Block Statement
In the days of writing DAOs via native JDBC, programmers feared nothing more than concatenating SQL statements, concatenating parameters and Settings to return result sets. Hibernate has made concatenating SQL a thing of the past. With ORM, you don’t need to deal with any SQL at all, but this brings new problems. Inability to write custom SQL results in loss of flexibility and better performance. MyBatis addresses this with mapper mapping SQL. Instead of concatenating SQL in JAVA code, it saves a lot of development time by moving it to mapper file centralization to process SQL.
Elements in Mapper:
- Cache – The cache configuration for a given namespace.
- ResultMap – Result set mapping.
- SQL – reusable block of statements that can be referenced by other statements.
- Insert – Insert statement
- Update – Update statement
- Delete – Deletes a statement
- Select – A query statement
Select usage and attributes
Example:
<select id="selectById" resultType="com.niuh.mybatis.dao.Account">
select * from account where id = #{id}
</select>
Copy the code
Properties:
<select
id="selectById"<! -- The unique identifier of the statement block corresponds to the method name in the interface --> parameterType="User"<! -- Parameter Java type --> resultType="hashmap"<! Return result Java type --> resultMap="userResultMap"<! FlushCache = flushCache="false"<! --true flushes the first and second caches on each call --> useCache="true"<! --true Whether to save to level 2 cache --> timeout="10"
statementType= PREPARED">
Copy the code
Insert&update & delete usage
Example:
<insert id="addUser" keyColumn="id" keyProperty="id" useGeneratedKeys="true"
parameterType="com.niuh.mybatis.dao.User">
insert into user (name,updateTime,createTime) values (#{name},#{updateTime},#{createTime})
</insert>
Copy the code
Properties:
<insert
id="addUser"<! -- The unique identifier of the statement block corresponds to the method name in the interface --> parameterType="User"<! -- Parameter Java type --> flushCache="true"<! --true flushes the primary and secondary caches with each call --> statementType="PREPARED"< Execution type > keyProperty=""<! -- Java properties corresponding to the primary key, multiple comma separated --> keyColumn=""<! -- Primary key column, multiple comma separated --> useGeneratedKeys=""<! -- After successful insertion, the value is set back to the original parameter -> timeout="20">
Copy the code
3.2 Parameter Mapping
Parameter mapping reference
Parameter mapping is one of the most powerful features, and bases can be referenced in the following ways
- Single simple parameter reference: If only one parameter in a method can be referenced by any name
- Multiple simple parameter references: reference #{arg0} #{arg1} or #{param1},#{param2} by parameter subscript
- Object attribute reference: directly referenced by object attribute name, nested object through. Number for reference
- Map key reference:
- Variable name reference (jdK1.8 support) : Reference by method parameter name, jdK1.8 support, and must be compiled with -parameters command
Add compilation parameters to IDEA
Add build parameters in Maven
Note: One but can be introduced by variable name is not available in support of arg0! Parameters reference related attributes javaType=int, # parameter Java type jdbcType=NUMERIC,# JDBC type typeHandler=MyTypeHandler# Specifies the type processor
Parameter splicing ${}
Parameter references based on # work by passing? Placeholders can be preprocessed for better performance and security (to prevent SQL injection), but some requirements are passed? For example, we need dynamic splicing table structure in some scenarios with separate tables. For example, if the systemlog table is 2018_systemlog,2019_systemlog can pass
Example:
@Select("SELECT * FROM ${table} WHERE id = #{id}")
User selectByTable(String table, int id);
Copy the code
3.3 Result set mapping
ResultSet mapping refers to encapsulating and converting contents in a resultSet into Java objects. In the pure JDBC era, getXXX(columnName) of a resultSet is called to obtain attributes and encapsulate them. It’s a lot of code, it’s a lot of inefficient programming especially if the data model is one to many, or many to many, this kind of encapsulation of code becomes very complicated. Result set mapping is designed to solve this problem by processing the relationship between result sets and JAVA objects in a resultMap.
Automatic mapping of result sets
If resultType= “” is specified in the SELECT, no configuration is required. MyBatis automatically generates an implicit resultMap based on the JAV type and attribute in the resultType to complete the result mapping
resultMap
But sometimes JDBC doesn’t fit perfectly with Java Beans and you need to manually set the resultMap
<resultMap id="account2" type="com.niuh.mybatis.dao.Account">
<id property="id"/>
<result property="createTimestamp" column="createTimestamp"
typeHandler="com.niuh.mybatis.dao.LongTimeHandler"/>
</resultMap>
Copy the code
ResultMap =”account2″ in the SELECT element can reference the map.
Base elements and attributes
- ID: Unique identifier used in the result set
- Result: Sets a certain pass field
property: jdbcType: javaType: column: typeHandler:
Nested result mappings
Association example:
<resultMap id="accountAndUser" type="com.niuh.mybatis.dao.Account">
<id property="id" column="id"/>
<association property="user" javaType="com.niuh.mybatis.dao.User">
<id property="id" column="user_id"/>
<result property="name" column="userName"/>
</association>
</resultMap>
<select id="selectAccountAndUser" resultMap="accountAndUser">
SELECT a.*, b.name userName from account a,user b where a.user_id=b.id
</select>
Copy the code
Introducing external Select
<! --> <resultMap ID ="accountAndUser2" type="com.niuh.mybatis.dao.Account">
<id property="id" column="id"/>
<association property="user" javaType="com.niuh.mybatis.dao.User" select="selectUser" column="user_id">
</association>
</resultMap>
<select id="selectUser" resultType="com.niuh.mybatis.dao.User">
select * from user where id = #{id}
</select>
Copy the code
A collection of the collection
1. Write the attributes of the collection element directly as the word tag of the collection
<resultMap type="com.niuh.mybatis.dao.User" id="userMap">
<id property="id" column="uid"/>
<result property="username" column="username"/>
<result property="password" column="password"/>
<collection property="roles" ofType="com.niuh.mybatis.dao.Role">
<id property="id" column="rid"/>
<result property="name" column="rname"/>
<collection property="permissions" ofType="com.niuh.mybatis.dao.Permissions">
<id property="id" column="pid"/>
<result property="name" column="pname"/>
</collection>
</collection>
</resultMap>
Copy the code
When a User is assigned a Set roles Role, a Set permissions can be assigned to all of the User attributes through a multi-table lookup.
Here is the query statement:
<select id="queryUserName" parameterType="string" resultMap="userMap">
SELECT u.*,r.*,p.* FROM user u inner join user_role ur on ur.uid=u.uid
inner join role r on r.rid=ur.rid
inner join permissions_role pr on pr.rid=r.rid
inner join permissions p on pr.pid=p.pid
WHERE username=#{username};
</select>
Copy the code
2, by referring to other mapper query methods in the collection tag
<resultMap id="BaseResultMap" type="com.niuh.mybatis.dao.SysUser" >
<id column="user_id" property="id" jdbcType="BIGINT" />
<result column="username" property="username" jdbcType="VARCHAR" />
<result column="password" property="password" jdbcType="VARCHAR" />
<collection property="sysRoles" column="user_id"
select="com.niuh.mybatis.dao.SysRoleMapper.selectRoleListByUserId">
</collection>
</resultMap>
Copy the code
SysRoles (selectRoleListByUserId); sysRoles (selectRoleListByUserId);
Here are the query statements: we just need to query SysUser
<select id="findByUsername" resultMap="BaseResultMap">
SELECT
us.id as user_id,
us.username,
us.password
FROM t_sys_user us WHERE us.username = #{username}
</select>
Copy the code
SelectRoleListByUserId = selectRoleListByUserId = selectRoleListByUserId = selectRoleListByUserId
<resultMap id="roleResult" type="com.niuh.mybatis.dao.SysRole">
<id property="id" column="role_id" jdbcType="BIGINT"/>
<result property="name" column="name" jdbcType="VARCHAR"/>
<result property="desc" column="desc" jdbcType="VARCHAR"/>
<collection property="permissions" column="role_id"
select="com.niuh.mybatis.dao.SysPermissionMapper.selectPermissionByRoleId">
</collection>
</resultMap>
<select id="selectRoleListByUserId" resultMap="roleResult">
SELECT
ro.id as role_id,
ro.name,
ro.desc
FROM t_sys_user_role ur
LEFT JOIN t_sys_role ro
ON ur.`role_id` = ro.`id` WHERE ur.user_id = #{userId}
</select>
Copy the code
Likewise, permissions in sysRoles are the same. Both methods can be implemented. The second method does not require writing overly complex SQL, and the methods in each Mapper can be used independently, making it more applicable.