5、解决属性名和字段名不一致的问题(ResultMap)
我们复制一份上面的项目,名字叫项目2,在项目2中做一点更改。
1、问题
在项目1中,我们的实体类pojo/User中的属性是和数据库中的字段一一对应的
在项目2中,我们修改实体类的pwd属性为password,重新生成构造方法和getter和setter,现在实体类中的属性与数据库中的字段不能完全匹配上了。
这是我们不做其他的修改,运行根据id查询用户信息的方法,查看结果:
我们发现测试方法虽然可以正常执行,但是,password字段为null了,这是为什么?
2、解决方案
首先来看上面password字段变为了空的原因。
在UserMapper.xml中根据id查询用户信息是这个sql
<select id="getUserById" parameterType="int" resultType="user">
select * from mybatis.user where id = #{id};
</select>
我们转换一下,实际查询的是这个
<select id="getUserById" parameterType="int" resultType="user">
select id,name,pwd from mybatis.user where id = #{id};
</select>
这就不难看出,因为pwd可以从数据库中查出,但是User对象中却不是这个字段,而是password,因此password就没有值了所以为空。
2.1、解决方案一
既然在查询的结果中没有password字段,那我们就把pwd重命名为password,让password这个字段存在。我们修改UserMapper.xml中的查询sql:
<select id="getUserById" parameterType="int" resultType="user">
select id,name,pwd as password from mybatis.user where id = #{id};
</select>
再运行测试方法,发现password结果可以正常展示了
2.2、解决方案二
虽然上面的方法有效,但是略显简单粗暴了点,Mybatis中可以使用ResultMap来对变量做映射关系。
我们修改UserMapper.xml中的mapper如下:
<mapper namespace="com.luca.dao.UserMapper">
<resultMap id="userResultMap" type="user">
<!--column指的是数据库中的字段名,property指的是实体类中的属性名-->
<result column="pwd" property="password" />
</resultMap>
<select id="getUserById" parameterType="int" resultType="user" resultMap="userResultMap">
select * from mybatis.user where id = #{id};
</select>
</mapper>
在mapper中新建了一个resultMap,命名为userResultMap,在里面配置了数据库字段pwd和实体类属性password的映射关系,然后在select 中指定使用的resultMap为它。
这样我们重新运行下测试方法,password也可以正常查询出来。
6、日志
在前面的例子中我们一直都是使用sout的方式打印我们需要的信息,但是这样的方式既不够详细也不够规范。在下面我们引入日志的方式来打印需要展示的信息。
首先复制一份上面例子的module,避免代码杂乱,同样的,针对com.luca.dao下的UserMapper创建测试方法,确保测试方法正常运行。
拷贝出来的代码结构如下:
我么再查看Mybatis的官方文档,其中就有关于日志的配置,其中logImpl就是用来配置日志的。
文档中列出了这些可配置的日志选项,我们下面会介绍Log4j和STDOUT_LOGGING两种方式:
- SLF4J
- LOG4J *
- LOG4J2
- JDK_LOGGING
- COMMONS_LOGGING
- STDOUT_LOGGING *
- NO_LOGGING
6.1、日志工厂
我们先看比较简单的STDOUT_LOGGING
方式,首先我们需要在mybatis-config.xml中增加配置
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
注意:setting标签需要放在properties和typeAliases标签中间,否则IDE会报红提示
不需要做其他的配置,我们再次运行test下的单元测试方法,查看输出的结果:
这次输出的结果不仅仅有数据库查询的结果,还有很多其他的信息,mybatis在查询出数据前后做了很多其他的工作:打开JDBC连接、创建连接、关闭自动提交、preparing的sql语句、sql查询的参数、查询出数据、关闭连接、归还连接池......
可以看到,在console中输出了比原来详细的多的信息。
6.2、Log4j
1. Log4j是什么
Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件,甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等;我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。-- 百度百科
从百度百科的解释中可以大概看出log4j:
- 是Apache的开源项目
- 可以控制输出日志到控制台、文件等等
- 可以配置每一条日志的输出格式和级别
- 通过配置文件来实现,不需要修改应用的代码
2. 使用Log4j
下面我们尝试在现在的模块中使用log4j,首先必不可少的当然是导包:
pom.xml
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
然后我们在resources下创建log4j的配置文件:
log4j.properties
### 设置###
log4j.rootLogger = debug,stdout,D,E
### 输出信息到控制台 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n
### 输出DEBUG 级别以上的日志到=logs/debug.log ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = logs/luca.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
### 输出ERROR 级别以上的日志到=logs/error.log ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File =logs/luca.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
最后在mybatis-config.xml中修改setting使用的日志方式为log4j
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
好了,我们再运行下测试方法:
可以看到,console中同样打印出了十分详细的信息,并且是按照我们配置文件中设置的格式输出。另外,在项目的根目录下,可以看到创建了一个logs目录,下面存放了对应的debug和error级别的日志。
除了打印mybatis的debug日志,我们还可以在自己打印需要的信息,创建测试方法如下:
package com.luca.dao;
import com.luca.dao.UserMapper;
import com.luca.pojo.User;
import com.luca.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;
import org.junit.Test;
public class TestUserMapper {
static Logger logger = Logger.getLogger(TestUserMapper.class);
@Test
public void TestLog4jOutput() {
logger.info("This is a info level info");
logger.debug("This is a debug level info");
logger.error("This is a error level info");
}
}
我们在测试方法中输出了不同级别的信息,需要注意的是Logger引用的是log4j.Logger,否则会有问题。运行测试方法,在console中和logs/luca.log中都可以看到我们打印的信息。
7、分页
7.1、Limit实现分页
看到分页首先想到的就是下面这样的SQL语句,那么在Mybatis中实现分页也就是这样的一句sql:
select * from user limit 0, 2;
还是三步走:
-
创建UserMapper接口
com/lucal/dao/UserMapper
//分页查询用户 List<User> getUserByLimit(Map<String, Integer> map);
-
实现UserMapper.xml文件
com/lucal/dao/UserMapper.xml
<select id="getUserByLimit" parameterType="map" resultMap="userResultMap"> select * from mybatis.user limit #{startIndex}, #{pageSize} </select>
在这里我们传递参数使用的是前面提到的”万能的Map“,其中传入分页查询的开始下标和查询大小。
-
测试
test/com/luca/dao/TestUserMapper
@Test public void TestGetUserByLimit() { SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); HashMap<String, Integer> map = new HashMap<>(); map.put("startIndex", 0); map.put("pageSize", 2); List<User> userList = mapper.getUserByLimit(map); for (User user : userList) { System.out.println(user); } sqlSession.close(); }
执行测试方法,可以看到查询的结果和输入的分页参数预期结果一致:
7.2、RowBounds实现分页
除了使用上面手写limit语句进行分页,Mybatis中内置了RowBounds方式进行分页,但是由于这种方式是查询出所有的数据再进行切分来实现分页的,所以在查询数据量大的时候并不建议使用它。我们直接来看使用方法,只要在接口中传入一个RowBounds对象即可:
UserMapper.java
//使用RowBounds分页查询用户
List<User> getUserByRowBounds(RowBounds rowBounds);
UserMapper.xml
<select id="getUserByRowBounds" resultMap="userResultMap">
select * from mybatis.user
</select>
TestUserMapper.java
@Test
public void TestGetUserByRowBounds() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> users = mapper.getUserByRowBounds(new RowBounds(3, 2));
for (User user : users) {
System.out.println(user);
}
sqlSession.close();
}
7.3、PageHelper实现分页
除了上面两种方式,在企业中也有很多使用PageHelper进行分页,这里不做介绍,等有需要的时候跟着官方文档学习吧~