认识Mybatis
MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以对配置和原生Map使用简单的 XML 或注解,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>x.x.x</version>
</dependency>
Mybatis的功能架构
我们把Mybatis的功能架构分为三层:
- API接口层:提供给外部使用的接口API,开发人员通过这些本地API来操纵数据库。接口层一接收到调用请求就会调用数据处理层来完成具体的数据处理。
- 数据处理层:负责具体的SQL查找、SQL解析、SQL执行和执行结果映射处理等。它主要的目的是根据调用的请求完成一次数据库操作。
- 基础支撑层:负责最基础的功能支撑,包括连接管理、事务管理、配置加载和缓存处理,这些都是共用的东西,将他们抽取出来作为最基础的组件。为上层的数据处理层提供最基础的支撑。
准备数据库
DROP TABLE IF EXISTS `country`;
CREATE TABLE `country` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`countryname` varchar(255) DEFAULT NULL,
`countrycode` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
INSERT INTO country(countryname,countrycode)values
('中国','CN'),('美国','US'),('俄罗斯','RU'),('英国','GB'),('法国','FR');
准备好表和简单的数据后,我们再来使用MyBatis。
配置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>
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
<typeAliases>
<package name="com.leesanghyuk.modle"/>
</typeAliases>
<!-- 配置mybatis运行环境 -->
<environments default="development">
<!-- 配置开发环境 -->
<environment id="development">
<!-- jdbc事务管理器 -->
<transactionManager type="JDBC"/>
<!-- 数据源
UNPOOLED 不适用连接池 即 每次请求都会为其创建一个DB连接,适用完毕后,会马上将连接关闭
POOLED 数据库连接池来维护连接
JNDI 数据源可以定义到应用的外部,通过JDNI容器来获取数据库连接
-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
<property name="username" value="root"/>
<property name="password" value="woshixiao"/>
</dataSource>
</environment>
</environments>
<!-- 映射器 -->
<mappers>
<!-- 注册映射文件 -->
<mapper resource=""/>
</mappers>
</configuration>
简单解释下这个配置:
<setting>
中的logImpl属性配置指定使用LOG4J输出日志。<typeAliases>
元素下面配置了包名,通常确定一个类的时候需要写包名+类名,我们配置包名后,只需要写上类名即可。<enviroment>
环境配置中主要配置了数据库连接。<mappers>
里面配置映射器。
创建实体类和Mapper.xml文件
mybatis是一个结果映射框架,这里创建的实体类实际上是一个数据值对象(Data Value Object),在实际应用中,一个表通常会对应一个实体,用增删改查来操作,所以姑且称为实体类。
关于Mapper 的命名方式:在MyBatis 中,根据MyBatis 官方的习惯,一般用Mapper 作为XML 和接口类名的后缀,这里的Mapper 和我们常用的DAO 后缀类似,只是一种习惯而已,本书中全部使用Mapper 后缀。通常称XML 为Mapper.xml 文件,称接口为Mapper 接口,在实际应用中可以根据自己的需要来定义命名方式。
我们在Model包中创建实体类Country:
package com.leesanghyuk.model;
public class Country {
private Long id;
private String countryname;
private String countrycode;
...
}
我们在resource下面创建一个mapper目录,再添加CountryMapper.xml文件:
<?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">
<mapper namespace="com.leesanghyuk.mapper.CountryMapper">
<select id="selectAll" resultType="Country">
SELECT id,countryname,countrycode from country
</select>
</mapper>
再解释下这个:
<mapper>
:XML的根元素,namespace定义了当前xml的命名空间。<select>
:我们所定义的查询语句,id
属性定义了当前的id,resultType
定义了当前查询的返回值类型,此处就是指实体类Country。因为前面设置了包名了,所以这里只需要类名。
接下来有针对性的配置log4j,让mybatis在执行数据库操作的时候能够将执行的SQL和其他信息输出到控制台。
配置LOG4J
添加一个log4j.properties配置文件,输入以下内容:
#全局配置
log4j.rootLogger=ERROR, stdout
#MyBatis日志设置
log4j.logger.mapper=TRACE
#控制台输出配置
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] -%m%n
用过Log4j 日志组件的人可能都会知道,配直中的log4j.logger.mapper 对应的是mapper包,但是在这个例子中,Java 目录下并没有这个包名,只在资源目录下有maoper 目录。
在MyBatis 的日志实现中,所谓的包名实际上是XML 配直中的Namespace 属性值的一部分。后面章节中介绍结合接口使用的相关内容时,由于Name space 属性值必须和接口全限定类名相同,因此才会真正对应 Java 中的包。当使用纯注解方式时,使用的就是纯粹的包名。
MyBatis 日志的最低级别是TRACE ,在这个日志级别下, MyBatis 会输出执行SQL 过程中的详细信息,这个级别特别适合在开发时使用。
接下来我们让Mybatis跑起来
编写测试代码
package com.leesanghyuk.mapper;
import com.leesanghyuk.model.Country;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.junit.BeforeClass;
import java.io.IOException;
import java.io.Reader;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import static org.junit.Assert.*;
public class CountryMapperTest {
private static SqlSessionFactory sqlSessionFactory;
@BeforeClass
public static void init(){
try {
Reader reader=Resources.getResourceAsReader("mybatis_config.xml");
sqlSessionFactory=new SqlSessionFactoryBuilder().build(reader);
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
@Test
public void testSelectAll(){
SqlSession sqlSession=sqlSessionFactory.openSession();
List<Country> countryList=sqlSession.selectList("selectAll");
printCountryList(countryList);
sqlSession.close();
}
private void printCountryList(List<Country> countryList){
for (Country c:countryList) {
System.out.printf("%-4d%4s%4s\n",c.getId(),c.getCountryname(),c.getCountrycode());
}
}
}