MyBatis
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.
I. Overview of the framework
Frameworks typically lie in the middle layer between low-level application platforms (such as J2EE) and high-level business logic.
1. Three-tier architecture
- Presentation layer: For display control
- Business layer: Handles business logic requirements
- Persistence layer: Interaction with the database
2. Persistence layer technical solution
3. MyBatis framework
MyBatis framework uses ORM to solve the problem of entity and database mapping. It internally encapsulates the complex process of JDBC driver loading, connection creation, statement creation and so on, and shields the low-level access details of JDBCAPI so that developers only need to pay attention to THE SQL statement itself.
MyBatis configures various statements to be executed through XML or annotations, and generates the final SQL statement by mapping Java objects to the dynamic parameters of the SQL in the statement. Finally, the MYBatis framework executes the SQL and maps the results to Java objects and returns them.
ORM: Object Relational Mappging Object Relational mapping
We divide the functional architecture of Mybatis into three layers:
- API Interface layer: Interface apis for external use by developers to manipulate the database through these native apis. As soon as the interface layer receives the call request, it calls the data processing layer to complete the specific data processing.
- Data processing layer: responsible for specific SQL lookup, SQL parsing, SQL execution and execution result mapping processing, etc. Its main purpose is to complete a database operation based on the request of the call.
- Base support layer: Responsible for the most basic functional support, including connection management, transaction management, configuration loading, and cache handling, all of which are common and extracted as the most basic components. It provides the most basic support for the upper data processing layer.
2. Simple case analysis
1. Environment construction
1.1 Preparations: Create a database
CREATE DATABASE javaee; Create database
USE javaee; -- Use database
Create table user
DROP TABLE IF EXISTS `user`
CREATE TABLE `user` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`username` VARCHAR(32) NOT NULL COMMENT 'User name'.`birthday` DATETIME DEFAULT NULL COMMENT 'birthday'.`sex` CHAR(1) DEFAULT NULL COMMENT 'gender'.`address` VARCHAR(256) DEFAULT NULL COMMENT 'address',
PRIMARY KEY (`id`))ENGINE=INNODB DEFAULT CHARSET=utf8;
Add data
INSERT INTO `user`(`id`.`username`.`birthday`.`sex`.`address`) VALUES (41.'Lao wang'.'the 2018-02-27 17:47:08'.'male'.'Beijing'), (42.'Little Two Kings'.'the 2018-03-02 15:09:37'.'woman'.'Beijing Jinyanlong'), (43.'Little Two Kings'.'the 2018-03-04 11:34:34'.'woman'.'Beijing Jinyanlong'), (45.'Pass the Wisdom Podcast'.'the 2018-03-04 12:04:06'.'male'.'Beijing Jinyanlong'), (46.'Lao wang'.'the 2018-03-07 17:37:26'.'male'.'Beijing'), (48.'Little Pony'.'the 2018-03-08 11:44:00'.'woman'.'Beijing Correction');
Copy the code
1.2 IDEA Creating a Maven project
-
Note and information filling in new project
- Don’t check
Create from archetype
- GroupId: com. Hihanying
- ArtifactId: javaee01_mybatis01_xml
- Don’t check
-
After the project is built, the pom. XML file configuration: Add the following content after
<packaging>jar</packaging> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.9</source> <target>1.9</target> <encoding>UTF-8</encoding> </configuration> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.2</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.6</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies> Copy the code
With MyBatis, you can also place the MyBatis -x.x.x.jar file in the classpath in addition to writing the coordinates to PM.xml.
2. Build the project framework
2.1 Project directory structure
2.2 Writing the User entity class:
-
Path: javaee01_mybatis01 \ SRC \ main \ Java \ com \ hihanying \ domain \ User. Java
-
Fields:
private Integer id; private String username; private Date birthday; private String sex; private String address; Copy the code
-
Alt+Insert inserts getter, setter, toString
2.3 Compiling persistence Layer interface files
-
Path: javaee01_mybatis01 \ SRC \ main \ Java \ com \ hihanying \ dao \ IUserDao Java
-
Name: Can be UserDao or UserMapper, personal custom
-
Code:
public interface IUserDao { List<User> findAll(a); } Copy the code
2.4 Writing a persistent layer interface mapping file
-
Path: javaee01_mybatis01 \ SRC \ main \ resources \ com \ hihanying \ dao \ IUserDao XML
The directory dictionary created in IDEA is different from the package
- The package is created by entering com.itheima.dao in a three-tiered structure
- When creating a directory, enter com.itheima.dao, a level 1 directory
-
Content:
<! DOCTYPEmapper PUBLIC "- / / mybatis.org//DTD Mapper / 3.0 / EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.hihanying.dao.IUserDao"> <select id="findAll" resultType="com.hihanying.domain.User"> select * from user </select> </mapper> Copy the code
-
Note:
- The mapping configuration file location of MyBatis must be the same as the package structure of the DAO interface
- The file name must be the name of the persistence layer interface with an.xml extension
- The value of the namespace attribute of the mapper tag in the mapping configuration file must be the fully qualified class name of the DAO interface
- The value of the operation configuration (Select tag) ID attribute of the mapping configuration file must be the method name of the DAO interface
2.5 Compiling the SQLmapconfig. XML configuration file
-
Path: javaee01_mybatis01 \ SRC \ main \ resources \ SqlMapConfig XML
-
Content:
<? 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> <! -- Configure the environment --> <environmentsdefault="mysql"> <! -- Configure the mysql environment --> <environment id="mysql"> <! <transactionManager type="JDBC"></transactionManager> <! --> <dataSource type="POOLED"> <! -- Configure the connection to the database4Basic types --> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/javaee"/> <property name="username" value="root"/> <property name="password" value="root"/> </dataSource> </environment> </environments> <mappers> <mapper resource="com/hihanying/dao/IUserDao.xml"/> </mappers> </configuration> Copy the code
3. Write test classes
3.1 Code Examples
Path: javaee01_mybatis01 \ SRC \ test \ Java \ com \ hihanying \ test \ MybatisTest Java
public class MybatisTest {
public static void main(String[] args) throws IOException {
// 1. Read the configuration file sqlmapconfig.xml
InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
// 2. Create the SqlSessionFactory factory from the configuration file
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(is);
// 3. Create an SqlSession object using the SqlSessionFactory
SqlSession sqlSession = factory.openSession();
// 4. Create a proxy object for the IUserDao interface using the SqlSession object
IUserDao userDao = sqlSession.getMapper(IUserDao.class);
// 5. Use the proxy object userDao to execute the method
List<User> users = userDao.findAll();
for (User user : users) {
System.out.println(user);
}
// 6. Release resourcessqlSession.close(); is.close(); }}Copy the code
3.2 Code Analysis
Reading configuration Files
- Use the class loader
- use
Resources.getResourceAsStream("SqlMapConfig.xml")
Should the importorg.apache.ibatis.io.Resources
The Resources utility class in MyBatis provides an easy-to-use method for loading Resources from the classpath. - This is equivalent to:
MybatisTest.class.getClassLoader().getResourceAsStream("SqlMapConfig.xml")
- use
SqlSessionFactory
-
SqlSessionFactory is the key object of Mybatis. It is the factory to create SqlSession. Every application of Mybatis takes an instance of SqlSessionFactory object as the core
- Action figure
- Sequence diagram
The SqlSessionFactory was created using the Builder mode
-
Builder pattern: Separate the construction of a complex object from its representation so that the same construction process can create different representations.
-
Build the factory object SqlSessionFactory based on different input parameters
-
Advantages: The details of creating objects are hidden, and users can call methods directly to retrieve objects
The creation of the SqlSession object, SqlSessionFactory itself, uses static/simple factory mode
-
In the simple factory pattern, you can return instances of different classes depending on the parameters. The simple factory pattern specifically defines a class that is responsible for creating instances of other classes, which usually have a common parent class.
-
SqlSessionFactory is an interface, it has two implementation class DefaultSqlSessionFactory. Java, SqlSessionManager. Java, Mybatis is using DefaultSqlSessionFactory. Java as its default implementation
-
The openSession method of SqlSessionFactory is heavily overloaded to support the input of parameters such as autoCommit, Executor, Transaction, etc., to build the core SqlSession object.
-
Advantage: Decoupling
The proxy mode is used to create the IUserDao interface implementation class
-
Proxy Pattern: Provides a Proxy for an object, and the Proxy object controls the reference to the original object.
-
Implementation process
In step 6, the MapperProxy object implements the InvocationHandler interface and implements the invoke method of that interface.
-
Advantage: The mapper.java interface class is simply written, and when a Mapper interface is actually executed, it is forwarded to the MapPerProxy.invoke method. This method calls a series of methods, such as SQLsession. cud > executor.execute > prepareStatement, to execute and return SQL. That is, without modifying the source code on the basis of the existing method is enhanced
4. Annotation-based approach
There are two caveats to MyBatis’ annotation approach
-
You don’t need the iUserDAo.xml file, just use the @SELECT annotation on the methods of the IUserDao interface and specify SQL statements
public interface IUserDao { @Select("select * from user") List<User> findAll(a); } Copy the code
-
Use the class attribute to specify the fully qualified class name of the IUserDao interface when mapper configuration is required in the SQLMapConfig.xml file.
<mappers> <mapper class="com.hihanying.dao.IUserDao"/> </mappers> Copy the code
3. Customize MyBatis framework
Objective: To deeply understand the implementation process of MyBatis
Procedure: The mybatis coordinates in the SQLmapconfig.xml configuration file are removed, and the classes in the Mybatis package used in the test code are customized
1. Project structure
The custom MyBatis framework will serve the following test code:
// 1. Read the configuration file sqlmapconfig.xml
InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
// 2. Create the SqlSessionFactory factory from the configuration file
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(is);
// 3. Create an SqlSession object using the SqlSessionFactory
SqlSession sqlSession = factory.openSession();
// 4. Create a proxy object for the IUserDao interface using the SqlSession object
IUserDao userDao = sqlSession.getMapper(IUserDao.class);
// 5. Use the proxy object userDao to execute the method
List<User> users = userDao.findAll();
Copy the code
The classes and interfaces involved in the above code are:
public class Resources
public class SqlSessionFactoryBuilder
public interface SqlSessionFactory
public interface SqlSession
Copy the code
The project structure is as follows, including the above classes and interfaces and the classes involved in the source code:
2. Implement the Resources class
The Resources class simply reads the configuration file SQLMapConfig.xml and returns an InputStream object through its getResourceAsStream method
public class Resources {
public static InputStream getResourceAsStream(String filePath) {
returnResources.class.getClassLoader().getResourceAsStream(filePath); }}Copy the code
3. Implement SqlSessionFactoryBuilder
The SqlSessionFactoryBuilder class is used to create the SqlSessionFactory object, which reads the InputStream object of the configuration file using the build method and returns an SqlSessionFactory object.
public class SqlSessionFactoryBuilder {
public SqlSessionFactory build(InputStream config) {
Configuration cfg = XMLConfigBuilder.loadConfiguration(config);
return newDefaultSqlSessionFactory(cfg); }}Copy the code
Reading the Configuration file involves parsing the XML file. Here we use the loadConfiguration method of the utility class XMLConfigBuilder, which returns a Configuration object containing the following information from the Configuration file
public class Configuration {
private String driver;
private String url;
private String username;
private String password;
private Map<String, Mapper> mappers = new HashMap<String, Mapper>();
// Note: Append assignments are used here, not directly, to prevent overwriting by multiple contents in mappers
public void setMappers(Map<String, Mapper> mappers) {
this.mappers.putAll(mappers); }}Copy the code
Where the first four String objects represent the four basic objects that are configured to connect to the database, the key in mappers object is the fully qualified class name and method name of dao, and Mapper is a custom object that includes queryString and resultType, Represents the fully qualified class name of the SQL statement to execute and the entity class to encapsulate, respectively
public class Mapper {
private String queryString;
private String resultType;
}
Copy the code
Once you get the Configuration object (that is, all the useful information in the Configuration file), you should return an SqlSessionFactory object, which creates the implementation class DefaultSqlSessionFactory for SqlSessionFactory
4. Implement SqlSessionFactory interface
The SqlSessionFactory interface should have an openSession method to create a new SqlSession object to operate on the database
public interface SqlSessionFactory {
SqlSession openSession(a);
}
Copy the code
Implementation: On the one hand, it receives the Configuration object passed when creating the SqlSessionFactory, and on the other hand, it passes the Configuration object to the newly created SqlSession object through the openSession method.
public class DefaultSqlSessionFactory implements SqlSessionFactory {
private Configuration cfg;
public DefaultSqlSessionFactory(Configuration cfg) {
this.cfg = cfg;
}
@Override
public SqlSession openSession(a) {
return newDefaultSqlSession(cfg); }}Copy the code
5. Implement the SqlSession interface
The SqlSession interface is the core class that interacts with the database
- The getMapper method is used to create a proxy object for the DAO, which takes the bytecode of the DAO interface and returns the proxy object for the DAO interface.
- The close method is used to release resources
public interface SqlSession {
<T> T getMapper(Class<T> daoInterfaceClass);
void close(a);
}
Copy the code
Implementation:
public class DefaultSqlSession implements SqlSession {
private Configuration cfg;
private Connection connection;
public DefaultSqlSession(Configuration cfg) {
this.cfg = cfg;
connection = DataSourceUtil.getConnection(cfg);
}
@Override
public <T> T getMapper(Class<T> daoInterfaceClass) {
return (T) Proxy.newProxyInstance(
daoInterfaceClass.getClassLoader(),
new Class[]{daoInterfaceClass},
new MapperProxy(cfg.getMappers(),connection));
}
@Override
public void close(a) {
if(connection ! =null) {
try {
connection.close();
} catch(SQLException e) { e.printStackTrace(); }}}}Copy the code
The constructor of DefaultSqlSession takes a Configuration object and converts it to a Connection, using the getConnection method in the utility class DataSourceUtil
public class DataSourceUtil {
public static Connection getConnection(Configuration cfg) {
try {
Class.forName(cfg.getDriver());
return DriverManager.getConnection(cfg.getUrl(),
cfg.getUsername(), cfg.getPassword());
} catch (SQLException | ClassNotFoundException e) {
throw newRuntimeException(e); }}}Copy the code
The DefaultSqlSession class overwrites the getMapper method to create a proxy object, where the parameter MapperProxy is defined as follows, and selectList is a method in the Executor utility class used to execute SQL statements and encapsulate result sets:
public class MapperProxy implements InvocationHandler {
private Map<String, Mapper> mappers;
private Connection conn;
public MapperProxy(Map<String, Mapper> mappers, Connection conn) {
this.mappers = mappers;
this.conn = conn;
}
// Used to enhance the method, that is, to call the selectList method
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
String className = method.getDeclaringClass().getName();
String key = className + '. ' + methodName;
Mapper mapper = mappers.get(key);
if (mapper ==null) {
throw new IllegalArgumentException("Incorrect parameter passed in");
}
return newExecutor().selectList(mapper,conn); }}Copy the code
4. Complete CRUD with Mybatis
-
Pay attention to
- Test the use of @before and @after in the program
- Use curly braces to read values
insert into user (username,sex,birthday,address) values (#{username},#{sex},#{birthday},#{address}) Copy the code
- The contents of the tables in the database should match the fields in the classes used in the code
-
Basic flow: Take adding a record to a database as an example
-
Add it to com\hihanying\dao\ iUserdao.xml
<select id="saveUser" resultType="com.hihanying.domain.User"> insert into user (username,sex,birthday,address) values (#{username},#{sex},#{birthday},#{address}) </select> Copy the code
-
Add the corresponding method in com\hihanying\dao\ iUserdao.java
void saveUser(User user); Copy the code
-
Test in test methods
@Test public void testSaveUser(a) throws IOException { User user = new User(); user.setSex("Male"); user.setBirthday(new Date()); user.setUsername("Should be cold"); user.setAddress("Weifang, Shandong Province"); mapper.saveUser(user); sqlSession.commit(); } Copy the code
- View the results in the SQL Visualization tool
-