mybatis
1, Introduction to mybatis
1. Dependencies that mybatis needs to import
<dependencies> <!--mysql drive--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.46</version> </dependency> <!--mybatis rely on--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.2</version> </dependency> <!--Test dependency--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> </dependencies>
2. Core profile
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 Core profile--> <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://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8"/> <property name="username" value="root"/> <property name="password" value="drldrl521521"/> </dataSource> </environment> </environments> <mappers> <mapper resource="org/mybatis/example/BlogMapper.xml"/> </mappers> </configuration>
3.util tools
Get sqlSession object
public class MybatisUtil { private static SqlSessionFactory sqlSessionFactory; static { try { //1. Get SqlSessionFactory object String resource="mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { e.printStackTrace(); } } public static SqlSession getSqlSession(){ return sqlSessionFactory.openSession(true); } }
4. Entity class
Rewrite the entity class set, get, toString, equal and other methods with lombok annotation
import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor public class User { private int id; private String name; private String pwd; }
lombok dependency
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.10</version> </dependency>
5.Dao interface and Mapper
public interface UserDao { //Add user public int addUser(User user); //Delete user by id public int deleteUserById(int id); //Update user information according to Id public int updateUserById(User user); //Query all users public List<User> getUserList(); //Query user by Id public User getUserById(int id); //Fuzzy query public List<User> getUserLike(String value); }
<?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"> <!--Equivalent to the original JDBC Implementation class of--> <!--namespace You need to bind a corresponding Dao/Mapper Interface--> <mapper namespace="com.drl.dao.UserDao"> <!-- select Query statement "id"Equivalent to interface method name "resultType"Is the result set. Fully qualified name is required --> <select id="getUserList" resultType="com.drl.entity.User"> select * from user; </select> <select id="getUserById" parameterType="int" resultType="com.drl.entity.User"> select * from user where id=#{id} </select> <!--Fuzzy query--> <select id="getUserLike" resultType="com.drl.entity.User"> select * from user where name like #{value} </select> <insert id="addUser" parameterType="com.drl.entity.User"> insert into user values(#{id},#{name},#{pwd}) </insert> <delete id="deleteUserById" parameterType="int"> delete from user where id=#{id} </delete> <update id="updateUserById" parameterType="com.drl.entity.User"> update user set name=#{name},pwd=#{pwd} where id=#{id} </update> </mapper>
6. Test
public class UserDaoTest { @Test public void test01(){ //1. Get sqlSession object SqlSession sqlSession = MybatisUtil.getSqlSession(); //2. Method 1: getMapper List<User> userList = sqlSession.getMapper(UserDao.class).getUserList(); for (User user:userList) { System.out.println(user); } //Close session sqlSession.close(); } @Test public void test02(){ SqlSession sqlSession=MybatisUtil.getSqlSession(); User user=sqlSession.getMapper(UserDao.class).getUserById(1); sqlSession.close(); System.out.println(user); } @Test public void test03(){ SqlSession sqlSession=MybatisUtil.getSqlSession(); sqlSession.getMapper(UserDao.class).addUser(new User(2,"Li Si","ls")); sqlSession.commit(); sqlSession.close(); } @Test public void test04(){ SqlSession sqlSession=MybatisUtil.getSqlSession(); int res=sqlSession.getMapper(UserDao.class).deleteUserById(2); if(res>0) { System.out.println("Delete succeeded!"); } sqlSession.commit(); sqlSession.close(); } @Test public void test05(){ SqlSession sqlSession=MybatisUtil.getSqlSession(); int res=sqlSession.getMapper(UserDao.class).updateUserById(new User(1,"Li Si","ls")); if(res>0){ System.out.println("Update succeeded!"); } sqlSession.commit(); sqlSession.close(); } @Test//Fuzzy query public void test06(){ SqlSession sqlSession=MybatisUtil.getSqlSession(); List<User> list=sqlSession.getMapper(UserDao.class).getUserLike("Lee"); for (User user:list){ System.out.println(user); } } }
7.ResultMap
<!--Result set mapping--> <resultMap id="map" type="User"> <!--column Fields in the index database, property Refers to an attribute in an entity class--> <result column="id" property="id"/> <result column="name" property="name"/> <result column="pwd" property="password"/> </resultMap> <select id="getUserList" resultMap="map"> select * from user; </select>
Note: when using resultMap, you can change which fields do not match, and the same fields do not need to be changed
<!--Result set mapping--> <resultMap id="map" type="User"> <!--column Fields in the index database, property Refers to an attribute in an entity class--> <result column="pwd" property="password"/> </resultMap> <select id="getUserList" resultMap="map"> select * from user; </select>
Possible problems
1.maven's agreement is larger than the configuration, and the configuration file written later may not be exported or effective
The error may exist in com/drl/dao/UserMapper.xml
The configuration file written by yourself does not exist, and idea does not detect it
Solution:
<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. Possible problems in creating maven project
Information:java: Errors occurred while compiling module 'mybatis-01' Information:javac 11 was used to compile java sources Information:Module "mybatis-01" was fully rebuilt due to project configuration/dependencies changes Information:2021/8/29 10:55 - Build completed with 1 error and 0 warnings in 3 s 953 ms Error:java: error: Release 5 is not supported
resolvent:
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>13</source> <target>13</target> </configuration> </plugin> </plugins> </build>
3. Fuzzy query
When performing fuzzy query, you need to add "%%" to the string of parameters for splicing,
@Test//Fuzzy query public void test06(){ SqlSession sqlSession=MybatisUtil.getSqlSession(); List<User> list=sqlSession.getMapper(UserDao.class).getUserLike("%Lee%"); for (User user:list){ System.out.println(user); }
The following fuzzy query statements are easy to be injected by SQL. This method is not used
<!--Fuzzy query--> <select id="getUserLike" resultType="com.drl.entity.User"> select * from user where name like #{value} </select>
Write "%%" to death. If you only need to pass the value, it will not be injected
<!--Fuzzy query--> <select id="getUserLike" resultType="com.drl.entity.User"> select * from user where name like "%"#{value}"%" </select>
4. Processed "possible problem 1", unable to find mapper for dao interface XML configuration file
Caused by: java.io.IOException: Could not find resource com.drl.dao.UserMapper.xml
resolvent:
The problem may be mybatis config There was a problem with the address when registering mapper in the XML file
The following is a problem. You can't use "." in mapper To separate
<mappers> <mapper resource="com.drl.dao.UserMapper.xml"/> </mappers>
Correct as follows:
<mappers> <mapper resource="com/drl/dao/UserMapper.xml"/> </mappers>
5. When the field name in the database is inconsistent with the attribute name in the entity class
When the field name in the database is "pwd" and the entity class is "password", this field will be empty
2, Configuration optimization
1. Attribute configuration optimization
db.properties configuration file
driver=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8 username=root password=drldrl521521
Do not use dB Mybatis congif. Before properties XML file
<?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 Core profile--> <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://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8"/> <property name="username" value="root"/> <property name="password" value="drldrl521521"/> </dataSource> </environment> </environments> <mappers> <mapper resource="com/drl/dao/UserMapper.xml"/> </mappers> </configuration>
Introduce dB. In the core configuration file Mybatis config. After properties XML file
<?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 Core profile--> <configuration> <!--Import profile--> <properties resource="db.properties"/> <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://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8"/> <property name="username" value="root"/> <property name="password" value="drldrl521521"/> </dataSource> </environment> </environments> <mappers> <mapper resource="com/drl/dao/UserMapper.xml"/> </mappers> </configuration>
2. Alias
The first way to alias: give each class an alias
<!--Alias--> <typeAliases> <typeAlias type="com.drl.entity.User" alias="User"/> </typeAliases>
The second way to alias: scan the package, and the class name with the first letter of the alias in lowercase
<!--Alias--> <typeAliases> <package name="com.drl.entity"/> </typeAliases>
3. Log
In mybatis config Configuration in XML configuration file
[STDOUT_LOGGING]
<!--Introduce resources--> <properties resource="db.properties"/> <!--journal--> <settings> <setting name="logImpl" value="STDOUT_LOGGING"/> </settings> <!--Alias--> <typeAliases> <typeAlias type="com.drl.entity.User" alias="User"/> </typeAliases>
The log is printed on the console:
Opening JDBC Connection Created connection 16503286. Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@fbd1f6] ==> Preparing: select * from user; ==> Parameters: <== Columns: id, name, pwd <== Row: 1, Li Si, ls <== Row: 2, Li Wu, lw <== Total: 2 User(id=1, name=Li Si, pwd=ls) User(id=2, name=Li Wu, pwd=lw)
[LOG4J]
Add the dependency of LOG4J
<dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency>
Configuration file for LOG4J
log4j.properties
#Set the log level and output the log information with the level of DEBUG to the two destinations of console and file # console and file are defined in the following code log4j.rootLogger=DEBUG,console,file #Settings related to 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/drl.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
Set log4j in the mybatis core configuration file
<!--journal--> <settings> <setting name="logImpl" value="LOG4J"/> </settings>
4. Pagination
4.1 using limit paging
Mapper interface, using Map to pass parameters
//Paging query, using map to pass parameters public List<User> getUserByLimit(Map<String ,Object> map);
Write SQL statements, "startIndex" refers to the starting subscript (starting from 0), and "pageSize" refers to how much data is on each page
<!--Paging query--> <select id="getUserByLimit" parameterType="map" resultType="User"> select * from user limit #{startIndex},#{pageSize}; </select>
Testing
@Test//paging public void test02(){ SqlSession sqlSession=MybatisUtil.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); Map<String,Object> map=new HashMap<>(); map.put("startIndex",0); map.put("pageSize",2); List<User> userByLimit = mapper.getUserByLimit(map); for(User user:userByLimit){ System.out.println(user); } }
4.2 rowboundaries (obsolete)
4.3PageHelper paging plug-in
3, Using annotation development
When developing with annotations, UserMapper is not required XML configuration file, you can directly use annotations in the UserMapper interface, such as:
@Select("select * from user where id=#{id}") public User getUserById(int id);
In mybatis config UserMapper.xml does not need to be mapped in the core configuration file XML configuration file, but the UserMapper interface needs to be bound, such as:
<!--Binding interface--> <mappers> <mapper class="com.drl.dao.UserMapper"/> </mappers>
Annotations cannot handle more complex things, such as mapping result sets, and ResultMap cannot be implemented. If the database field name is inconsistent with the entity class attribute, the query data of some field names will be empty!
1.UserMapper annotation
public interface UserMapper { //increase @Insert("insert into user values(#{id},#{name},#{pwd})") public int addUser(User user); //Delete @Delete("delete from user where id=#{id}") public int deleteUserById(@Param("id") int id); //change @Update("update user set name=#{name},pwd=#{pwd} where id=#{id}") public int updateUserById(User user); //check @Select("select * from user where id=#{id}") public User getUserById(@Param("id") int id); }
2. Test
@Test//query public void test01(){ SqlSession sqlSession= MybatisUtil.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user = mapper.getUserById(2); sqlSession.close(); System.out.println(user); } @Test//increase public void test02(){ SqlSession sqlSession=MybatisUtil.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user=new User(3,"Zhang San","zs"); int res=mapper.addUser(user); System.out.println(res>0?"Increase success!":"Failed to add!"); } @Test//delete public void test03(){ SqlSession sqlSession=MybatisUtil.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); int res=mapper.deleteUserById(3); System.out.println(res>0?"Delete succeeded!":"Deletion failed!"); } @Test//change public void test04(){ SqlSession sqlSession=MybatisUtil.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user=new User(2,"Zhang San","zs"); int res=mapper.updateUserById(user); System.out.println(res>0?"Modification succeeded!":"Modification failed!"); }
3.@Param
1.@Param can only be placed before the basic type parameter of the method in the interface, but not before the reference type parameter
2. If there is only one parameter, @ Param may not be added, but it is recommended to add it
3. If there is @ Param annotation, the name in @ Param will overwrite the original name.
For example, the following code will make an error, and the "userId" in @ Param will be overwritten by "id", which cannot be found
@Delete("delete from user where id=#{id}") public int deleteUserById(@Param("userId") int id);
4, Complex query
Student list
Teacher table
It is very simple to query a single table, but when you want to query the student information with foreign keys and the corresponding teacher name, you can write SQL:
select s.id,s.name,s.tid,t.name from student s,teacher t where s.tid=t.id
But how to find it in mybatis?
1. Many to one
1.1 nested processing by query
Multiple students have one teacher, and one teacher teaches multiple students.
Student perspective: many to one, that is, association
Teacher's point of view: one to many, that is, collection
Entity class Student
@Data @NoArgsConstructor @AllArgsConstructor public class Student { private int id; private String name; private Teacher teacher; }
Entity class Teacher
@Data @AllArgsConstructor @NoArgsConstructor public class Teacher { private int id; private String name; }
StudentMapper interface
public interface StudentMapper { public List<Student> getStudent(); }
StudentMapper.xml file
Set the return type of the data to be queried to "ResultMap", and the object attribute is labeled with "association".
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!--configuration Core profile--> <mapper namespace="com.drl.dao.StudentMapper"> <select id="getStudent" resultMap="StudentTeacher"> select * from student </select> <resultMap id="StudentTeacher" type="com.drl.entity.Student"> <result property="id" column="id"/> <result property="name" column="name"/> <association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/> </resultMap> <select id="getTeacher" resultType="Teacher"> select * from teacher where id=#{id} </select> </mapper>
1.2 nesting according to results
StudentMapper interface
public List<Student> getStudent2();
StudentMapper.xml file
<!--Nested processing according to results--> <select id="getStudent2" resultMap="StudentTeacher2"> select s.id sid,s.name sname,t.name tname from student s,teacher t where s.tid=t.id </select> <resultMap id="StudentTeacher2" type="Student"> <result property="id" column="sid"/> <result property="name" column="sname"/> <association property="teacher" javaType="Teacher"> <result property="name" column="tname"/> </association> </resultMap>
2. One to many
2.1 nesting according to results
Entity class Student
@Data @NoArgsConstructor @AllArgsConstructor public class Student { private int id; private String name; private int tid; }
Entity class Teacher
@Data @AllArgsConstructor @NoArgsConstructor public class Teacher { private int id; private String name; //A teacher has multiple schools, one to many private List<Student> students; }
TeacherMapper interface
public interface TeacherMapper { //Query all student information and teacher information of the teacher public Teacher getTeachers(@Param("tid") int id); }
TeacherMapper.xml file
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!--configuration Core profile--> <mapper namespace="com.drl.dao.TeacherMapper"> <!--Nested query by result--> <select id="getTeachers" resultMap="TeacherStudent"> select s.id sid,s.name sname,t.name tname,t.id tid from student s,teacher t where s.tid=t.id and t.id=#{tid} </select> <resultMap id="TeacherStudent" type="Teacher"> <result property="id" column="tid"/> <result property="name" column="tname"/> <!-- Complex attributes should be handled separately. Objects: association Set: collection javaType="",Specifies the type of the property Generics in collections, using ofType obtain --> <collection ofType="Student" property="students"> <result property="id" column="sid"/> <result property="name" column="sname"/> <result property="tid" column="tid"/> </collection> </resultMap> </mapper>
Results
Teacher(id=1, name=mary, students=[Student(id=1, name=Xiao Ming, tid=1), Student(id=2, name=Xiao Zhang, tid=1), Student(id=3, name=cockroach, tid=1), Student(id=4, name=petty thief, tid=1), Student(id=5, name=Xiao Wang, tid=1)])
5, Dynamic SQL
1.If label
Use the if tag to judge and then splice. When using the if tag, add a "where 1=1" after the original SQL statement for subsequent SQL splicing.
In addition, it is very convenient to pass parameters with map, which is more convenient than passing parameters with entity classes!
MapperBlog interface
List<Blog> queryBlogIf(Map<String,String> map);
MapperBlog.xml file
<select id="queryBlogIf" parameterType="map" resultType="Blog"> select * from blog where 1=1 <if test="title!=null"> and title=#{title} </if> <if test="author!=null"> and author=#{author} </if> </select>
Test class
@Test public void test02(){ SqlSession sqlSession=MybatisUtil.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); Map<String,String> map = new HashMap<>(); map.put("author","Rui Long Dong"); List<Blog> blogList = mapper.queryBlogIf(map); for (Blog blog : blogList) { System.out.println(blog); }
2.Where label
If the SQL in the if tag is used above, always add a sentence "where 1=1" to prevent subsequent SQL errors. If there is no "where 1=1", the following errors will be caused:
<select id="queryBlogIf" parameterType="map" resultType="Blog"> select * from blog where 1=1 <if test="title!=null"> and title=#{title} </if> <if test="author!=null"> and author=#{author} </if> </select>
In the first case, if only title has parameters, the SQL statement is as follows, and there is an obvious error:
select * from blog where and title=#{title}
In the second case, if only the author has parameters, the SQL statement is as follows, and there is an obvious error:
select * from blog where and author=#{author}
In the third case, if both title and author have parameters, the SQL statement is as follows, and there is an obvious error:
select * from blog where and title=#{title} and author=#{author}
To sum up, in order to prevent such problems, you can use the where tag:
<select id="queryBlogIf" parameterType="map" resultType="Blog"> select * from blog <where> <if test="title!=null"> title=#{title} </if> <if test="author!=null"> and author=#{author} </if> </where> </select>
If the title has no parameters and the author has parameters, the "and" in the subsequent splicing will be automatically removed from the where tag. The SQL is as follows and there will be no error:
select * from blog where author=#{author}
3.Choose label
In dynamic SQL, if you want to execute one SQL statement instead of all, you need to use the Chsoose tag.
BlogMapper interface
List<Blog> queryBlogChoose(Map<String,Object> map);
BlogMapper.xml file
<select id="queryBlogChoose" parameterType="map" resultType="Blog"> select * from blog <where> <choose> <when test="title!=null"> title=#{title} </when> <when test="author!=null"> and author=#{author} </when> <otherwise> and views=#{views} </otherwise> </choose> </where> </select>
The following points should be noted when using this label:
1. The choose tag and the where tag generally need to be used together
2.choose is equivalent to the "if... else" tag. If the previous conditions can be met, you don't have to judge whether the following conditions can be executed; If the conditions in "when" are not met, execute the SQL in "otherwise"; If all three conditions are met, the SQL in the first "when" is executed.
4.Set label
When using the update statement, you may be uncertain about the update field, so you can use the set tag.
BlogMapper interface
int updateBlog(Map<String,Object> map);
BlogMapper.xml file
<update id="updateBlog" parameterType="map"> update blog <set> <if test="title!=null"> title=#{title}, </if> <if test="author!=null"> author=#{author} </if> where id=#{id} </set> </update>
5.SQL fragment
When writing SQL statements, a large number of SQL statement fragments will be repeated. At this time, SQL fragments can be reused.
<sql id="if-title-author"> <if test="title!=null"> title=#{title} </if> <if test="author!=null"> and author=#{author} </if> </sql> <select id="queryBlogIf" parameterType="map" resultType="Blog"> select * from blog <where> <include refid="if-title-author"></include> </where> </select>
Related links:
1.mybatis official document address: https://mybatis.org/mybatis-3/zh/index.html