Mybatis
1. Introduction
1.1. What is Mybatis
- MyBatis is an excellent persistence layer framework
- It supports customized SQL, stored procedures, and advanced mapping.
- MyBatis avoids almost all JDBC code and manually setting parameters and getting results
- MyBatis can use simple XML or annotations to configure and map native types, interfaces and Java POJO s (Plain Old Java Objects) as records in the database.
- My'Batis was originally an open source project iBatis of apache. In 2010, the project was migrated from apache software foundation to google code and renamed MyBatis.
- Moved to Github in November 2013.
How do I get MyBatis?
-
maven warehouse:
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.6</version> </dependency>
-
Github: http://github.com/mybatis/mybatis-3/releases
-
Chinese documents: http://mybatis.org/mybatis-3/zh/index.html
1.2 persistence
Data persistence
-
Persistence is the process of transforming program data in persistent state and transient state
-
Memory: loss upon power failure
-
Two methods can be used for data persistence: 1. Database (jdbc) 2. io file persistence (too much resources).
-
Persistence in life: refrigerated, canned.
Why persistence?
- There are some objects that can't be thrown away.
- Memory is too expensive
1.3. Durable layer
-
Code block that completes the persistence work
-
The boundary of the layer is very obvious.
1.4 why do you need MyBatis?
- Help programmers store data into the database.
- convenient
- Traditional JDBC code is too complex. simplify. frame
- You can do without Mybatis
- advantage:
- Easy to learn
- flexible
- The separation of sql and code improves maintainability
- Provide mapping labels to support the mapping of orm fields between objects and databases
- Provide object relationship mapping labels to support object relationship component maintenance
- Provide xml tags to support writing dynamic sql.
2. The first Mybatis program
Idea: build environment – > Import Mybatis – > write code – > test!
2.1 construction environment
Build database
create database `mybatis`; user `mabatis`; create table `user`( `id` int(20) not null primary key, `name` varchar(30) default null, `pwd` varchar(30) default null )engine=innodb insert into `user` (`id`,`name`,`pwd`) values (1,'Zhang Shubo','123456')
New project
1. Create an ordinary Maven project
2. Delete src directory
3. Import maven dependency
<dependencies> <dependency> <grounpId>mysql</grounpId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <dependency> <grounpId>org.mybatis</grounpId> <artifactId>mybatis</artifactId> <version>3.5.2</version> </dependency> <dependency> <grounpId>junit</grounpId> <artifactId>junit</artifactId> <version>4,12</version> </dependency> </dependencies>
<!--stay build Medium configuration ersources,To prevent the failure of resource export--> <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> <filtering>true</filtering> </resource> </resources> </build>
2.2. Create a module
-
Write the core configuration file of mybatis
<?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"> <enviroment id="develoment"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.sql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatis useSSL=true&useUnicode=true&characterEncoding=UTF-8"/> <property name="username" value="root"/> <property name="password" value="root"/> </dataSource> </enviroment> </environments> <!--every last Mapper.xml All need to be in Mybatis Register in core file configuration--> <mappers> <mapper resource="route"/> </mappers> </configuration>
-
Write the tool class of mybatis
//Promote scope private static SqlSessionFactory sqlSessionFactory; static{ try{ //Step 1 of using Mybatis: get sqlSessionFactory object String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); }catch (IOException e){ e.printStackTrace(); } }
2.3. Code writing
Entity class
Dao interface
public interface UserDao{List<User> getUserList();}
Interface implementation class
<?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"> <!--namespace=Bind a corresponding Dao/Mapper Interface--> <mapper namespace="catalogue"> <select id="Interface method name" resultType="Return value, the directory of the entity class"> select * from mybatis.user </select> </mapper>
2.4 test
Note:
org.apache.ibatis.binding,BindingException:Type interface path is not known to the MapperRegistry
What is MapperRegistry?
Register mappers in the core configuration file
-
junit test
@Test public void test(){ //Step 1: get SqlSession object SqlSession sqlSession = MybatisUtils.getSqlSession(); //Step 2: getMapper try{ UserDao userDao = sqlSession.getMapper(UserDao.class); List<User> userList = userDao.getUserList(); for(User user:userList){ System.out.println(user); } }catch(Exception e){ e.printStackTrace(); }finally{ //Close SqlSession sqlSession.close(); } } //Officials suggest try, because try to close the flow
Possible problems:
1. The profile is not registered
2. Binding interface error
3. Wrong method name
4. Wrong return type
5.Maven export resource problem
3,CRUD
1,namespace
The package name in namespace should be consistent with the package name of Dao/mapper interface!
2,select
- id: is the method name in the corresponding namespace
- resultType: return value of Sql statement execution
- parameterType: parameter type
1. Write interface
//Query user by ID User getUserById(int id);
2. Write the sql statement in the corresponding mapper
<select id="getUserById" parameterType="int" resultType="Entity class path"> select * from mybatis.user where id = #{id}; </select>
3. Test
@Test public void getUserById(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user = mapper.getUserById(1); System.out.println(user); sqlSession.close(); }
3,Insert
<!--The properties in the object can be taken out directly--> <insert id="addUser" paramaterType="Returns the path of the value type entity class object"> insert into mybatis.user (id,name,pwd) valuse (${id},${name},${pwd}); </insert>
4,Update
<update id="updateUser" parameterType="Returns the path of the value type entity class object"> update mybatis.user set name=#{name},pwd=#{pwd} where id = #{id}; </update>
5,Delete
<delete id="deleteUser" parameterType="int"> delete from mybatis.user where id = #{id}; </delete>
Note: add, delete and modify transactions need to be submitted!!!!
6. Universal Map
Assuming that there are too many tables, fields or parameters in our entity class or database, we should refer to Map!
//Universal Map int addUser2(Map<String,Object> map);
<!--The properties in the object can be directly taken out and passed map of key--> <insert id="addUser" parameterType="map"> insert into mybatis.user (id,pwd) values (#{userid},#{password}); </insert>
@Test public void addUser2(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); Map<String,Object> map = new HashMap<String,Object>(); map.put("userid",5); map.put("password","123456"); mapper.addUser2(map); sqlSession.close(); }
Pass parameters from map and directly get the key from sql! [parameterType=“map”]
Pass parameters to the Object and directly get the attribute of the Object in sql [parameterType = "Object"]
If there is only one basic data type, you can get it directly in sql!
Use Map or annotation for multiple parameters!
7. Fuzzy query
How to write fuzzy query?
1. Pass the wildcard%% when executing Java code
List<User> userList = mapper.getUserLike("%Zhang%");
2. Use wildcards in sql splicing
select * from mybatis.user where name like "%"#{value}"%";
4. Configuration resolution
1. Core profile
-
mybatis-config.xml
-
The MyBatis configuration file contains settings and attribute information that deeply affect MyBatis behavior.
configuration(Configuration) properties(Properties) settings(Settings) typeAliases(Type alias) typeHandlers(Type (processor) objectFactory(Object factory) plugins(Plug in) environments(Environment configuration) environment(Environment variables) transactionManager(Transaction manager) dataSource((data source) databaseIdProvider(Database (vendor identification) mappers(Mapper)
2. Environment configurations
MyBatis can be configured to adapt to a variety of environments
However, remember that although multiple environments can be configured, only one environment can be selected for each SqlSessionFactory instance
Learn to use and configure multiple operating environments
Mybatis default transaction manager: JDBC connection pool: POOLED
3. properties
We can reference the configuration file through the properties property
These properties are externally configurable and dynamically replaceable. They can be configured in a typical Java property file or passed through the child elements of the properties element. [db.properties]
The content of element type configuration must match (properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objectWrapperFactory?,reflectorFactory?,plugins?,environments?,databaseIdProvider?,mappers?,). This is the configuration order
db.properties
jdbc.driver=com.mysql.jdbc.Driver jdbc.username=root jdbc.password=root jdbc.url=jdbc:mysql://localhost:3306/teaching_system?useSSL=false
Mapping in core configuration file
<!--Import external profile--> <properties resource="db.properties"> <property name="username" value="root"/> <property name="pwd" value="111111"/> </properties>
- You can import external files directly
- You can add some attribute configurations in the
- If two files have the same field, the external configuration file is preferred!
4. Type aliases
-
A type alias is a short name for a Java type
-
The meaning of existence is only to reduce the redundancy of class fully qualified names
<!--You can alias an entity class--> <typeAliases> <typeAlias type="Entity class path" alias="User" /> </typeAliases>
You can also specify a package name. MyBatis will search for the required Java beans under the package name, such as:
Scan the package of an entity class, and its default alias is the class name of this class, with the first letter in lowercase!
<!--You can alias an entity class--> <typeAliases> <package name="Path to package" /> </typeAliases>
The first method is used when there are few entity classes
If there are many entity classes, the second one is recommended.
Difference: the first can be a DIY alias, while the second cannot. If you have to change it, you need to add annotations on the entity
@Alias("user") public class User{}
5. Set
These are extremely important tuning settings in MyBatis, which change the runtime behavior of MyBatis
[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-jqdfktkk-1624853580603) (C: \ users \ Dell \ appdata \ roaming \ typora user images \ image-20210627115801276. PNG)]
[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-wpemp14l-1624853580604) (C: \ users \ Dell \ appdata \ roaming \ typora \ typera user images \ image-20210627115837803. PNG)]
6. Other settings
- typeHandlers
- objectFactory (object factory)
- plugins plug-in
- mybatis-generator-core
- mybatis-plus
- General mapper
7. mappers
MapperRegistry: register and bind our Mapper file:
Method 1: (recommended)
<!--every last Mapper.xml All need to be in Mybatis Register in the core configuration file!--> <mappers> <mapper resource="xml Profile path" /> </mappers>
Method 2: register with class file binding
<!--every last Mapper.xml All need to be in Mybatis Register in the core configuration file!--> <mappers> <mapper class="class route" /> </mappers>
Method 3: use scanning package for injection binding
<!--every last Mapper.xml All need to be in Mybatis Register in the core configuration file!--> <mappers> <package name="Package path" /> </mappers>
Points for attention in the latter two methods:
- Interface and its Mapper configuration file must have the same name
- Interface and its Mapper configuration file are in the same package!
8. Lifecycle and scope
[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-2n9x6w4q-1624853580605) (C: \ users \ Dell \ appdata \ roaming \ typora user images \ image-20210627155009181. PNG)]
Lifecycle and scope are crucial, because incorrect use can lead to very serious concurrency problems.
SqlSessionFactoryBuilder:
- Once SqlSessionFactory is created, it is no longer needed
- local variable
SqlSessionFactory:
- To be clear, it can be imagined as: database connection pool
- Once SqlSessionFactory is created, it should always exist during the operation of the application. There is no reason to discard it or recreate another instance
- Therefore, the best scope of SqlSessionFactory is the application scope
- The simplest is to use singleton mode or static singleton mode
SqlSession:
- A request to connect to the connection pool!
- The instance of SqlSession is not thread safe, so it cannot be shared, so its best scope is the request or method scope
- You need to close it immediately after use, otherwise the resources will be occupied!
[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-4bqzaeed-1624853580607) (C: \ users \ Dell \ appdata \ roaming \ typora \ user images \ image-20210627160331423. PNG)]
Each Mapper in this represents a specific business
5. Solve the problem of inconsistency between attribute name and field name
1. Question
Fields in the database
[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-brzfkrtu-1624853580608) (C: \ users \ Dell \ appdata \ roaming \ typora \ user images \ image-20210627160905408. PNG)]
Create a new project and test the inconsistency of entity class fields before copying
public class User{ private int id; private String name; private String password; }
There is a problem with the test
[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-ntqxx9hh-1624853580609) (C: \ users \ Dell \ appdata \ roaming \ typora \ user images \ image-20210627161307894. PNG)]
select * from mybaits.user where id = #{id} Type processor select id,name,pwd from mybatis.user where id = #{id}
Solution:
-
Alias
<select id="getUserById" resultType="Returns the entity class path of the object"> select id,name,pwd as password from mybatis,user where id = #{id} </select>
2,resultMap
Result set mapping
id name pwd id name password
<!--Result set mapping--> <resultMap id="UserMap" type="User"> <!--column Fields in the database, property Properties in entity classes--> <!-- <result column="id" property="id" /> --> <!-- <result column="name" property="name" /> --> <result column="password" property="password" /> </resultMap> <select id="getUserById" resultMap="UserMaps"> select * from mybatis.user where id = #{id} </select>
- The resultMap element is the most important and powerful element in MyBatis
- The design idea of ResultMap is that there is no need to configure the displayed result map for simple statements, but only need to describe their relationship for more complex statements.
- The best thing about realtmap is that although you already know it well, you don't need to use them explicitly
- If only the world were always so simple
6. Log
6.1 log factory
If an exception occurs in a database operation, we need to troubleshoot it. Log is the best assistant!
Once: system out,println ,debug
Now: log factory
[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-iqnut2mm-1624853580611) (C: \ users \ Dell \ appdata \ roaming \ typora \ user images \ image-20210627115801276. PNG)]
- SLF4J
- LOG4J
- LOG4J2
- JDK_LOGGING
- COMMONS_LOGGING
- STDOUT_LOGGING
- NO_LOGGING
Which log implementation to use in Mybatis can be set in settings!
STDOUT_LOGGING standard log output
In the mybatis core configuration file, configure our logs!
<settings> <setting name="logImpl" value="STDOUT_LOGGING" /> </settings>
[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-p9k3mv1j-1624853580612) (C: \ users \ Dell \ appdata \ roaming \ typora user images \ image-20210627165500312. PNG)]
6.2,Log4j
What is Log4j?
- Log4j is an open source project of Apache. By using log4j, we can control that the destination of log information transmission is console, file and GUI components
- We can control the output format of each log
- By defining the level of each log information, we can more carefully control the log generation process
- Configure flexibly through a configuration file without modifying the application code
1. Import the dependency of log4j first
<!-- https://mvnrepository.com/artifact/log4j/log4j --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency>
2.log4j.properties
#Output the log information with the level of DEBUG to the two destinations of console and file. The definitions of console and file are in the following code log4j.rootLogger=DEBUG,console,file #Relevant settings of console output log4j.appender.console = org.apache.log4j.ConsoleAppender log4j.appender.console.Target = System.out log4j.appender.console.Threshold=DEBUG log4j.appender.console.layout = org.apache.log4j.PatternLayout log4j.appender.console.layout.ConversionPattern = [%c]-%m%n #Settings related to file output log4j.appender.file = org.apache.log4j.RollingFileAppender log4j.appender.file.File=./log/kuang.log log4j.appender.file.MaxFileSize=10mb log4j.appender.file.Threshold=DEBUG log4j.appender.file.layout=org.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n #Log output level log4j.logger.org.mybatis=DEBUG log4j.logger.java.sql=DEBUG log4j.logger.java.sql.Statement=DEBUG log4j.logger.java.sql.ResultSet=DEBUG log4j.logger.java.sql.PreparedStatement=DEBUG
3. Configure log4j as the implementation of log
<settings> <setting name="logImpl" value="" /> </settings>
4. Use log4j to test and run query statements
Simple use
1. In the class to use Log4j, import the package import org apache. log4jLogger;
2. Log object. The parameter is the class of the current class
static Logger logger = Logger.getLogger(UserDaoTest.class);
3. Log level
logger.info("info:Entered testLog4j"); logger.debug("debug:Entered testLog4j"); logger.error("error: Entered testLog4j");
7. Pagination
Think: why pagination?
- Reduce data processing
7.1. Use limit paging
select * from user limit startIndex,pageSize
Pagination using Mybatis, core SQL
1. Interface
//paging List<User> getUserByLimit(Map<String,Integer> map);
2.Mapper.xml
<!--paging--> <select id="getUserByLimit" parameterType="map" resultMap="UserMap"> select* from mybatis.user limit #{startIndex},#{pageSize} </select>
3. Test
@Test public void getUserByLimit(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); HashMap<String,Integer> map = new HashMap<String,Integer>(); map.put("startIndex",1); map.put("pageSize",2); List<User> userList = mapper.getUserByLimit(map); for(User user: userList){ System.out.println(user); } sqlSession.close(); }
7.2 rowboundaries paging
No longer use SQL for paging
1. Interface
//Pagination 2 List<User> getUserByRowBounds();
2.mapper.xml
<!--Pagination 2--> <select id="getUserByRowBounds" resultMap="UserMap"> select * from mybatis.user </select>
3. test
@Test public void getUserByRowBounds(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); //RowBounds implementation RowBounds rowBounds = new RowBounds(0,2); //Paging through Java code level List<User> userList = sqlSession.selectList("com.dao.UserMapper.getUserByRowBounds",null,rowBounds); for(User user: userList){ System.out.println(user); } sqlSession.close(); }
7.3 paging plug-in
[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-nraayxbj-1624853580613) (C: \ users \ Dell \ appdata \ roaming \ typora user images \ image-20210627191348385. PNG)]
website: https://pagehelper.github.io/
8. Using annotation development
8.1 interface oriented programming
-
We have all learned face-to-face object programming and interface before, but in real development, we often choose interface oriented programming
-
Root cause: decoupling, expandable, improved reuse. In layered development, the upper layer does not care about the specific implementation. Everyone abides by common standards, making the development easier and better in scope
-
In an object-oriented system, various functions of the system are completed by many different objects. In this case, how each object implements itself is not so important for system designers
-
The cooperative relationship between various objects has become the key of system design. From the communication between different classes to the interaction between various modules, we should focus on it at the beginning of system design, which is also the main work of system design. Interface oriented programming is programmed according to this idea.
Understanding of interfaces
-
From a deeper understanding, the interface should be the separation of definition (specification, constraint) and Implementation (the principle of separation of name and reality)
-
The interface itself reflects the system designer's abstract understanding of the system
-
There shall be two types of interfaces:
- The first type is the abstraction of an individual, which can correspond to an abstract class
- The second is the abstraction of one aspect of an individual pair, that is, to form an abstract interface
- An individual may have multiple Abstract surfaces, which are distinguished by
Three oriented differences
- Object oriented means that when we consider a problem, we take the object as the unit and consider its attributes and methods
- Process oriented means that when we consider a problem, we consider its implementation in a specific process (transaction process)
- Interface design and non interface design are aimed at reuse technology. They are not a problem with object-oriented (process), but the overall architecture of the system
8.2 development using annotations
1. Annotation is implemented on the interface
@Select("select * from user") Lsit<User> getUsers();
2. The interface needs to be bound in the core configuration file
<!--Binding interface--> <mappers> <mapper class="dao Layer path" /> </mappers>
3. test
Essence: reflection mechanism implementation
Bottom layer: dynamic proxy
[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-mn76myvc-1624853580613) (C: \ users \ Dell \ appdata \ roaming \ typora user images \ image-20210628104738976. PNG)]
8.3,CRUD
We can automatically commit transactions when the tool class is created!
public static SqlSession getSqlSession(){ return sqlSessionFactory.openSession(true); }
Write the interface and add comments
public interface UserMapper{ @select("select * from user") List<User> getUsers(); //Method has multiple parameters. All parameters must be preceded by @ Param("id") annotation @select("select * from user where id = #{id}") User getUserByID(@Param("id") int id); @Insert("insert into user(id,name,pwd) values (#{id},#{name},#{password})") int addUser(User user); @Update("update user set name=#{name},pwd=#{password} where id =#{id}") int updateUser(User user); @Delete("delete from user where id = #{uid}") int deleteUser(@Param("uid") int id); }
Test class:
[Note: we must bind the interface registration to our core configuration file!]
About @ Param() annotation
- Parameters of basic type or String type need to be added
- Reference types do not need to be added
- If there is only one basic type, it can be ignored, but it is recommended to add it
- What we refer to in SQL is the attribute name set in @ Param()!
#{} ${} difference
- #{} when referencing, if it is found that the target is a string, its value will be spliced on the sql as a string, that is, quotation marks will be automatically wrapped during splicing
- When ${} is referenced, even if it is found that the target is a string, it will not be processed as a string, and quotation marks will not be automatically wrapped when splicing in sql