MyBatis-04-实用技巧
Posted primabrucexu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MyBatis-04-实用技巧相关的知识,希望对你有一定的参考价值。
五、ResultMap——结果集映射
- 解决属性名和字段名不一致的问题
5.1 查询为null的问题
-
什么时候会出现这个问题?
- 实体类中设置的属性名和数据库中的字段名不一致
-
问题复现
-
数据库中字段设置
-
实体类中的属性设置
public class User { private int id; private String name; private String password; }
-
查询测试
@Test public void test() { SqlSession sqlSession = MyBatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); List<User> list = mapper.getUsers(); for (User user : list) { System.out.println(user); } sqlSession.close(); }
-
从查询结果中可以看出,数据库中的pwd字段没有正确映射到实体类中的password属性上
-
5.2 问题分析
-
对SQL语句的分析:
select * from user <==> select id,name,pwd from user
-
MyBatis通过查询语句中的字段,去对应的实体类中查找相应属性名的set方法。但是,在本例中,实体类中没有pwd的set方法,所以字段pwd的值无法赋值给实体类,也就造成了查询结果中放回为null的情况
-
解决方法
-
指定别名,使得别名和java类中的属性名一一对应
-
使用结果集进行映射
<resultMap id="UserMap" type="User"> <!-- column是数据库表的列名, property是对应实体类的属性名--> <id column="id" property="id"/> <result column="name" property="name"/> <result column="pwd" property="password"/> </resultMap>
-
5.3 ResultMap
resultMap
元素是 MyBatis 中最重要最强大的元素。- 它可以让你从 90% 的 JDBC
ResultSets
数据提取代码中解放出来,并在一些情形下允许你进行一些 JDBC 不支持的操作。 - 实际上,在为一些比如连接的复杂语句编写映射代码的时候,一份
resultMap
能够代替实现同等功能的数千行代码。 - ResultMap的设计思想
- 对简单的语句做到零配置
- 对于复杂一点的语句,只需要描述语句之间的关系
1. 自动映射
-
对于简单的语句,我们可以不用手动配置ResultMap,因为ResultMap的自动映射完全可以满足我们的需求,我们需要做的就是确保属性名和查询到的字段名能一一对应上即可
-
示例
- 数据库的字段名
-
实体类
public class User { private int id; private String name; private String pwd; public User() { } }
-
mapper.xml
<select id="getUsers" resultType="com.pbx.pojo.User"> select * from user </select>
-
测试
@Test public void test() { SqlSession sqlSession = MyBatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); List<User> list = mapper.getUsers(); for (User user : list) { System.out.println(user); } sqlSession.close(); }
-
如果说实体类中的属性和数据库的字段不同,可以在SQL设置别名进行匹配
-
简单来说,如果你的SQL语句足够简单,那么完全不需要手动配置ResultMap,可以通过SQL设置别名来使得自动装配可以正确执行。
2. 简单的手动映射
-
示例
- mapper.xml
<resultMap id="userResultMap" type="User"> <id property="id" column="user_id" /> <result property="username" column="user_name"/> <result property="password" column="hashed_password"/> </resultMap> <select id="selectUsers" resultMap="userResultMap"> select user_id, user_name, hashed_password from some_table where id = #{id} </select>
-
注意点
- 在引用它的语句中设置
resultMap
属性就行了(注意去掉了resultType
属性)
- 在引用它的语句中设置
六、日志与分页
6.1 日志功能
-
MyBatis支持日志记录功能,需要在mybatis-config.xml文件中配置相应的参数以开启日志功能
-
mybatis-config.xml配置
<settings> <setting name="logImpl" value="STDOUT_LOGGING"/> </settings>
-
MyBatis支持的日志类型
SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING
-
日志输出示例
- 除了用户的输出之外,其余内容均是日志内容
6.2 log4j日志
- 通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件,甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等
- 我们也可以控制每一条日志的输出格式
- 通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。
- 通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。
使用步骤
-
在maven中导入log4j的依赖
<dependencies> <!-- https://mvnrepository.com/artifact/log4j/log4j --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> </dependencies>
-
在mybatis-config.xml中开启日志记录功能
<settings> <setting name="logImpl" value="LOG4J"/> </settings>
-
编写log4j.properties配置文件
### set log levels ### log4j.rootLogger = debug , stdout , D , E ### 输出到控制台 ### log4j.appender.stdout = org.apache.log4j.ConsoleAppender log4j.appender.stdout.encoding = UTF-8 log4j.appender.stdout.Target = System.out log4j.appender.stdout.layout = org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern = %d{ABSOLUTE} %5p %c{1}:%L - %m%n ### 输出到日志文件 ### log4j.appender.D = org.apache.log4j.DailyRollingFileAppender log4j.appender.D.encoding = UTF-8 log4j.appender.D.File = logs/log.log log4j.appender.D.Append = true log4j.appender.D.Threshold = DEBUG log4j.appender.D.layout = org.apache.log4j.PatternLayout log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n ### 保存异常信息到单独文件 ### log4j.appender.E = org.apache.log4j.DailyRollingFileAppender log4j.appender.E.encoding = UTF-8 log4j.appender.E.File = logs/error.log log4j.appender.E.Append = true log4j.appender.E.Threshold = ERROR log4j.appender.E.layout = org.apache.log4j.PatternLayout log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
6.3 分页
1. 使用LIMIT进行分页
- ·在SQL层面上进行分页操作
2. 使用RowBounds进行分页
-
目前已经不流行了,这是通过Java代码实现的
-
mapper接口
List<User> getUserByRowBounds();
-
mapper.xml文件
<select id="getUserByRowBounds" resultType="user"> select * from user </select>
-
测试类
@Test public void testUserByRowBounds() { SqlSession session = MybatisUtils.getSession(); int currentPage = 2; //第几页 int pageSize = 2; //每页显示几个 RowBounds rowBounds = new RowBounds((currentPage-1)*pageSize,pageSize); //通过session.**方法进行传递rowBounds,[此种方式现在已经不推荐使用了] List<User> users = session.selectList("com.kuang.mapper.UserMapper.getUserByRowBounds",null, rowBounds); for (User user: users){ System.out.println(user); } }
3. 使用插件PageHelper
七、使用注解开发
7.1 面向接口编程
-
目的:解耦,可拓展,提高代码复用
- 在分层开发中,上层不用管下层的具体实现,大家都会遵守共同的标准,简化开发
-
在一个面向对象的系统中,系统的各种功能是由许许多多的不同对象协作完成的。在这种情况下,各个对象内部是如何实现自己的,对系统设计人员来讲就不那么重要了;
-
各个对象之间的协作关系则成为系统设计的关键。小到不同类之间的通信,大到各模块之间的交互,在系统设计之初都是要着重考虑的,这也是系统设计的主要工作内容。面向接口编程就是指按照这种思想来编程。
-
什么是接口
- 接口从更深层次的理解,应是定义(规范,约束)与实现(名实分离的原则)的分离。
- 接口的本身反映了系统设计人员对系统的抽象理解。
- 接口应有两类:
- 第一类是对一个 个体的抽象,它可对应为一个抽象体(abstract class)
- 第二类是对一个 个体某一方面的抽象,即形成一个抽象面(interface)
7.2 MyBatis中的注解开发
-
对于像 BlogMapper 这样的映射器类来说,还有另一种方法来完成语句映射。 它们映射的语句可以不用 XML 来配置,而可以使用 Java 注解来配置。比如,上面的 XML 示例可以被替换成如下的配置:
public interface BlogMapper { @Select("SELECT * FROM blog WHERE id = #{id}") Blog selectBlog(int id); }
-
对于简单的语句,使用注解可以加快开发速度。但对于一些复杂的SQL语句,注解就显得力不从心
-
MyBatis的详细执行流程
7.3 CRUD操作
-
mapper接口文件
package com.pbx.mapper; import com.pbx.pojo.User; import org.apache.ibatis.annotations.*; import java.util.List; import java.util.Map; /** * @author BruceXu * @since 2020/10/30 */ public interface UserMapper { @Select("select * from user") List<User> getUsers(); @Select("select * from user where id = #{pid}") User getUserByID(@Param("pid") int id); @Insert("insert into user (id,name,pwd) values (#{id}, #{name}, #{pwd})") int insert(User user); @Update("update user set name = #{newName} where id = #{id}") int update(@Param("newName") String name, @Param("id") int id); @Delete("delete from user where id = #{id}") int delete(@Param("id") int id); }
-
注册mapper文件
<mappers> <mapper class="com.pbx.mapper.UserMapper"/> </mappers>
-
测试类
package com.pbx; import com.pbx.mapper.UserMapper; import com.pbx.pojo.User; import com.pbx.utils.MyBatisUtils; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.List; /** * @author BruceXu * @date 2020/11/3 */ public class test { @Test public void test() { SqlSession session = MyBatisUtils.getSqlSession(); UserMapper mapper = session.getMapper(UserMapper.class); List<User> list = mapper.getUsers(); for (User user : list) { System.out.println(user); } System.out.println("============================="); mapper.insert(new User(5, "bf", "123")); User t = mapper.getUserByID(5); System.out.println(t); System.out.println("============================="); mapper.update("gf", 5); t = mapper.getUserByID(5); System.out.println(t); System.out.println("============================="); mapper.delete(5); list = mapper.getUsers(); for (User user : list) { System.out.println(user); } System.out.println("============================="); session.commit(); session.close(); } }
7.4 @Param注解
- @Param用于指定接口中参数在SQL映射的名字
- 只有一个参数时,可以不使用(建议还是用上,养成习惯)
- 在方法有多个参数时,基本类型+String需要使用@Param进行标注名称
以上是关于MyBatis-04-实用技巧的主要内容,如果未能解决你的问题,请参考以下文章