您的位置:首页 > 运维架构 > Apache

Mybatis从入门到精通 (一)

2017-08-12 17:55 183 查看

Mybatis

Mybatis简介

MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。

MyBatis 是支持普通SQL、存储过程以及高级映射的优秀的持久层框架。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集,使开发者只需要关注sql本身。MyBatis 使用简单的 XML 或注解用于配置和原始映射,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。

Mybatis架构



1、mybatis配置SqlMapConfig.xml,此文件作为mybatis的全局配置文件,配置了mybatis的运行环境等信息。mapper.xml文件即sql映射文件,文件中配置了操作数据库的sql语句。此文件需要在SqlMapConfig.xml中加载。

2、通过mybatis环境等配置信息构造SqlSessionFactory即会话工厂

3、由会话工厂创建sqlSession即会话,操作数据库需要通过sqlSession进行。

4、mybatis底层自定义了Executor执行器接口操作数据库,Executor接口有两个实现,一个是基本执行器、一个是缓存执行器。

5、Mapped Statement也是mybatis一个底层封装对象,它包装了mybatis配置信息及sql映射信息等。mapper.xml文件中一个sql对应一个Mapped Statement对象,sql的id即是Mapped statement的id。

6、Mapped Statement对sql执行输入参数进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql前将输入的java对象映射至sql中,输入参数映射就是jdbc编程中对preparedStatement设置参数。

7、Mapped Statement对sql执行输出结果进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql后将输出结果映射至java对象中,输出结果映射过程相当于jdbc编程中对结果的解析处理过程。


Mybatis入门

我们先来写一个入门程序,来了解一下Mybatis具体的使用流程,具体的细节会在后面一一讲解。

第一步:创建数据库及数据库表,以供我们来操作。

CREATE DATABASE mybatis;
CREATE TABLE `user` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`username` VARCHAR(32) NOT NULL COMMENT '用户名称',
`birthday` DATE DEFAULT NULL COMMENT '生日',
`sex` CHAR(1) DEFAULT NULL COMMENT '性别',
`address` VARCHAR(256) DEFAULT NULL COMMENT '地址',
PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8;

INSERT INTO `user` VALUES ('1', '王五', NULL, '2', NULL);
INSERT INTO `user` VALUES ('10', '张三', '2014-07-10', '1', '北京市');
INSERT INTO `user` VALUES ('16', '张小明', NULL, '1', '河南郑州');
INSERT INTO `user` VALUES ('22', '陈小明', NULL, '1', '河南郑州');
INSERT INTO `user` VALUES ('24', '张三丰', NULL, '1', '河南郑州');
INSERT INTO `user` VALUES ('25', '陈小明', NULL, '1', '河南郑州');
INSERT INTO `user` VALUES ('26', '王五', NULL, NULL, NULL);


第二步:创建java项目,创建Mybatis核心配置文件sqlMapConfig.xml
SqlMapConfig.xml是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>
<!-- 和spring整合后 environments配置将废除 -->
<environments default="development">
<environment id="development">
<!-- 使用jdbc事务管理 -->
<transactionManager type="JDBC" />
<!-- 数据库连接池 -->
<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="123456" />
</dataSource>
</environment>
</environments>
</configuration>


第三步:创建和数据库表对应的pojo类

public class User implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private Integer id;
private String username;// 用户姓名
private String sex;// 性别
private Date birthday;// 生日
private String address;// 地址

public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "User [id=" + id + ", username=" + username + ", sex=" + sex
+ ", birthday=" + birthday + ", address=" + address + "]";
}
}


第四步:创建sql映射文件User.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">

<!-- namespace:命名空间,用于隔离sql,还有一个很重要的作用,后面会讲 -->
<mapper namespace="test">
<!--id为sql语句的id,parameterType为参数类型,resultType为结果类型,#{}为占位符-->
<!--根据id查找用户,#{}里面可以随便写-->
<select id="findUserById" parameterType="Integer" resultType="com.cad.domain.User">
select * from user where id =#{id}
</select>
</mapper>


第五步:sqlMapConfig配置文件中要引入映射文件

<mappers>
<mapper resource="sqlmap/User.xml"/>
</mappers>


第六步,测试程序,简单的操作

public class MybatisTest {

@Test
public void test() throws IOException {

String resource="config/sqlMapConfig.xml";
//加配置文件
InputStream in=Resources.getResourceAsStream(resource);
//创建SqlSessionFactoryBuilder对象用来创建工厂
SqlSessionFactoryBuilder builder= new SqlSessionFactoryBuilder();
//创建工厂
SqlSessionFactory factory=builder.build(in);
//创建Session
SqlSession sqlSession=factory.openSession();
//进行查询
User user=(User)sqlSession.selectOne("test.findUserById",1);
System.out.println(user);
sqlSession.close();
}
}


模糊查询

<select id="findUserByUsername" parameterType="String" resultType="com.cad.domain.User">
<!-- ${}里面只能是value -->
select * from user where username like '%${value}%'
</select>


public class MybatisTest {

@Test
public void test() throws IOException {
String resource="config/sqlMapConfig.xml";
InputStream in=Resources.getResourceAsStream(resource);
SqlSessionFactoryBuilder builder= new SqlSessionFactoryBuilder();
SqlSessionFactory factory=builder.build(in);
SqlSession sqlSession=factory.openSession();
List<User> users=sqlSession.selectList("findUserByUsername","五");
for(User user:users) {
System.out.println(user);
}
sqlSession.close();
}

}


添加

<!-- 添加操作 -->
<insert id="insertUser" parameterType="com.cad.domain.User">
insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})
</insert>


public class MybatisTest {

@Test
public void test() throws IOException {
String resource="config/sqlMapConfig.xml";
InputStream in=Resources.getResourceAsStream(resource);
SqlSessionFactoryBuilder builder= new SqlSessionFactoryBuilder();
SqlSessionFactory factory=builder.build(in);
SqlSession sqlSession=factory.openSession();
User user=new User();
user.setUsername("齐天大圣");
user.setBirthday(new Date());
user.setSex("男");
user.setAddress("花果山");
sqlSession.insert("insertUser", user);
sqlSession.commit();
sqlSession.close();
}

}


添加并返回数据库自增主键

<!-- 保存用户 -->
<insert id="saveUser" parameterType="cn.itcast.mybatis.pojo.User">
<!-- selectKey 标签实现主键返回 -->
<!-- keyColumn:主键对应的表中的哪一列 -->
<!-- keyProperty:主键对应的pojo中的哪一个属性 -->
<!-- order:设置在执行insert语句前执行查询id的sql,还是在执行insert语句之后执行查询id的sql -->
<!-- resultType:设置返回的id的类型 -->
<!--LAST_INSERT_ID():是mysql的函数,返回auto_increment自增列新记录id值。-->
<selectKey keyColumn="id" keyProperty="id" order="AFTER"
resultType="int">
SELECT LAST_INSERT_ID()
</selectKey>
INSERT INTO `user`
(username,birthday,sex,address) VALUES
(#{username},#{birthday},#{sex},#{address})
</insert>


修改

<!-- 修改操作 -->
<update id="updateUser" parameterType="com.cad.domain.User">
update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id=#{id}
</update>


public class MybatisTest {

@Test
public void test() throws IOException {
String resource="config/sqlMapConfig.xml";
InputStream in=Resources.getResourceAsStream(resource);
SqlSessionFactoryBuilder builder= new SqlSessionFactoryBuilder();
SqlSessionFactory factory=builder.build(in);
SqlSession sqlSession=factory.openSession();
User user=new User();
user.setId(27);
user.setUsername("天蓬元帅");
user.setBirthday(new Date());
user.setSex("女");
user.setAddress("银河");
sqlSession.update("updateUser", user);
sqlSession.commit();
sqlSession.close();
}

}


删除

<!-- 删除操作 -->
<delete id="deleteUser" parameterType="Integer">
delete from user where id=#{id}
</delete>


public class MybatisTest {

@Test
public void test() throws IOException {
String resource="config/sqlMapConfig.xml";
InputStream in=Resources.getResourceAsStream(resource);
SqlSessionFactoryBuilder builder= new SqlSessionFactoryBuilder();
SqlSessionFactory factory=builder.build(in);
SqlSession sqlSession=factory.openSession();
sqlSession.delete("deleteUser", 27);
sqlSession.commit();
sqlSession.close();
}

}


Mapper动态代理方式

Mapper接口开发方法只需要程序员编写Mapper接口(相当于Dao接口),由Mybatis框架根据接口定义创建接口的动态代理对象。

1.编写Mapper文件

<?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:命名空间,和Mapper接口的位置一样,这样框架会自动帮我们找到接口 -->
<mapper namespace="com.cad.domain.UserMapper">
<select id="findUserById" parameterType="int" resultType="com.cad.domain.User">
select * from user where id =#{id}
</select>

<!-- 模糊查询 -->
<select id="findUserByUsername" parameterType="String" resultType="com.cad.domain.User">
<!-- ${}里面只能是value -->
select * from user where username like '%${value}%'
</select>

<!-- 添加操作 --> <insert id="insertUser" parameterType="com.cad.domain.User"> insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address}) </insert>

<!-- 修改操作 --> <update id="updateUser" parameterType="com.cad.domain.User"> update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id=#{id} </update>

<!-- 删除操作 --> <delete id="deleteUser" parameterType="Integer"> delete from user where id=#{id} </delete>
</mapper>


2.创建Mapper接口

public interface UserMapper {
public User findUserById(int id);
public List<User> findUserByUsername(String username);
public void insertUser(User user);
public void deleteUser(Integer id);
}


3.核心配置文件中引入映射文件

<mappers>
<mapper resource="mapper/UserMapper.xml"/>
</mappers>


4.测试
public class MybatisTest {

@Test
public void test() throws IOException {
String resource="config/sqlMapConfig.xml";

InputStream in=Resources.getResourceAsStream(resource);
SqlSessionFactoryBuilder builder= new SqlSessionFactoryBuilder();
SqlSessionFactory factory=builder.build(in);
SqlSession sqlSession=factory.openSession();
UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
User user=userMapper.findUserById(10);
System.out.println(user);
}

}


Mapper接口开发需要遵循以下规范:

1、  Mapper.xml文件中的namespace与mapper接口的类路径相同,否则会找不到接口,也就无法生成代理对象。
2、  Mapper接口方法名和Mapper.xml中定义的每个方法的id相同
3、  Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同
4、  Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同


开发中使用这种方式来进行开发,简便快捷,代码复用性高,免去很多重复繁琐代码。

Mybatis一些小细节

通过入门例子可以知道,每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为中心的。SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先定制的 Configuration 的实例构建出 SqlSessionFactory 的实例。

从 XML 中构建 SqlSessionFactory

我们可以直接通过加载核心配置文件来创建SqlSessionFactory

String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);


不使用XML构建 SqlSessionFactory

//自己实现获取数据源
DataSource dataSource = xxx;
//获取事务
TransactionFactory transactionFactory = new JdbcTransactionFactory();
Environment environment = new Environment("development", transactionFactory, dataSource);
Configuration configuration = new Configuration(environment);
configuration.addMapper(BlogMapper.class);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);


configuration 添加了一个映射器类(mapper class)。映射器类是 Java 类,它们包含 SQL 映射语句的注解从而避免了 XML 文件的依赖。不过,由于 Java 注解的一些限制加之某些 MyBatis 映射的复杂性,XML 映射对于大多数高级映射来说仍然是必须的。有鉴于此,如果存在一个对等的 XML 配置文件的话,MyBatis 会自动查找并加载它(这种情况下, BlogMapper.xml 将会基于类路径和 BlogMapper.class 的类名被加载进来)。

了解即可,开发中使用xml格式。


主要类的生命周期

SqlSessionFactoryBuilder,这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了,可以重用 SqlSessionFactoryBuilder 来创建多个 SqlSessionFactory 实例,但是最好还是不要让其一直存在以保证所有的 XML 解析资源开放给更重要的事情。

SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由对它进行清除或重建。使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多

每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的。

每执行一次请求都应该开启一次sqlSession实例。当然要记得在finally中关闭来节省资源。

Mybatis的核心配置文件

MyBatis 的配置文件包含了MyBatis的设置和属性信息。文档的结构和顺序如下:

properties 属性
settings 设置
typeAliases 类型命名
typeHandlers 类型处理器
objectFactory 对象工厂
plugins 插件
environments(环境集合属性对象)
environment(环境子属性对象)
transactionManager(事务管理)
dataSource(数据源)
databaseIdProvider 数据库厂商标识
mappers 映射器


properties(属性)

我们可以将数据源等数据配置在外部文件中,然后引用。

//db.peoperties文件

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8
jdbc.username=root
jdbc.password=root


//引入文件
<properties resource="db.properties"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</dataSource>


如果属性在不只一个地方进行了配置,那么 MyBatis 将按照下面的顺序来加载:

在 properties 元素体内指定的属性首先被读取。

然后根据 properties 元素中的 resource 属性读取类路径下属性文件或根据 url 属性指定的路径读取属性文件,并覆盖已读取的同名属性。

typeAliases(类型别名)

类型别名是为 Java 类型设置一个短的名字。它只和 XML 配置有关,存在的意义仅在于用来减少类完全限定名的冗余。

<typeAliases>
<!-- 单个别名定义 -->
<typeAlias alias="user" type="cn.cad.pojo.User" />
<!-- 批量别名定义,扫描整个包下的类,别名为类名(大小写不敏感) -->
<package name="cn.itcast.mybatis.pojo" />
</typeAliases>

在mapper文件中就可以使用别名user。


Mybatis已经为许多常见的 Java 类型内建了相应的类型别名。它们都是大小写不敏感的,例如Srting,integer等。

插件(plugins)

MyBatis 允许你在已映射语句执行过程中的某一点进行拦截调用。默认情况下,MyBatis 允许使用插件来拦截的方法调用包括:

Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
ParameterHandler (getParameterObject, setParameters)
ResultSetHandler (handleResultSets, handleOutputParameters)
StatementHandler (prepare, parameterize, batch, update, query)


这些类中方法的细节可以通过查看每个方法的签名来发现,或者直接查看 MyBatis 的发行包中的源代码。 假设你想做的不仅仅是监控方法的调用,那么你应该很好的了解正在重写的方法的行为。 因为如果在试图修改或重写已有方法的行为的时候,你很可能在破坏 MyBatis 的核心模块。 这些都是更低层的类和方法,所以使用插件的时候要特别当心

配置环境(environments)

MyBatis 可以配置成适应多种环境,这种机制有助于将 SQL 映射应用于多种数据库之中, 现实情况下有多种理由需要这么做。例如,开发、测试和生产环境数据库需要有不同的配置

不过要记住:尽管可以配置多个环境,每个 SqlSessionFactory 实例只能选择其一。所以,如果你想连接两个数据库,就需要创建两个 SqlSessionFactory 实例,每个数据库对应一个。

配置环境的关键点:

默认的环境 ID(比如:default=”development”)。
每个 environment 元素定义的环境 ID(比如:id=”development”)。
事务管理器的配置(比如:type=”JDBC”)。
数据源的配置(比如:type=”POOLED”)


MyBatis 中有两种类型的事务管理器(也就是 type=”[JDBC|MANAGED]”)

Mybatis三种内建的数据源类型(也就是 type=”[UNPOOLED|POOLED|JNDI]”)

我们都是使用默认的,具体的参数意思可以查看官方文档。

映射器(mappers)

映射器配置会告诉了 MyBatis 去哪里找映射文件。

<mapper resource=" " />:使用相对于类路径的资源(现在的使用方式)

<mapper url="file:///var/mappers/AuthorMapper.xml"/>:使用绝对路径,基本不会用

<mapper class="cn.itcast.mybatis.mapper.UserMapper"/>:使用mapper接口类路径。注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。

<package name="xxx"/>:注册指定包下的所有mapper接口,此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息