简介
MyBatis是一款优秀的持久层框架,它支持自定义SQL,存储过程以及高级映射。MyBatis免除了几乎所有的JDBC代码以及设置参数和获取结果集的工作。MyBatis可以通过简单的XML或注解来配置和映射原始类型、接口和Java POJO为数据库中的记录。
入门
一、导入依赖
要使用mybatis,只需将mybatis的jar包置于类路径中。
如果使用Maven来建构项目,则需要将下面的依赖置于pom文件中:
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>x.x.x</version>
</dependency>
二、从XML中构建SqlSessionFactory
每个基于mybatis的应用都是以一个SqlSessionFactory的实例为核心。SqlSessionFactory的实例可以通过SqlSessionFactoryBuilder获得,而SqlSessionFactoryBuilder则可以从XML配置文件或一个预先配置的Configuration实例来构建出SqlSessionFactory实例。
从XML文件中构建SqlSessionFactory的实例很简单,可以使用类路径下的资源文件进行配置,也可以使用任意的输入流(inputStream)实例,比如文件路径字符串或file://URL构造的输入流。mybatis包含一个名叫Resources的工具类,它包含一些实用方法,使得从类路径或其他位置加载资源文件更加容易。
String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new
SqlSessionFactoryBuilder().build(inputStream);
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>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="org/mybatis/example/BlogMapper.xml"/>
</mappers>
</configuration>
将下面配置文件的一些信息替换成自己程序的信息。
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/database?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="password"/>
<mappers>
<mapper resource="usermapper.xml"/>
</mappers>
如此,mybatis已经配置完成。上述文件中,注意XML头部声明,它用来验证XML文档的正确性,environment元素中包含了事务管理和连接池的配置,mappers元素则包含了一组映射器,这些映射器的XML映射文件包含了SQL代码和映射定义信息。
三、从SqlSessionFactory中获取SqlSession
有了SqlSessionFactory就可以从中获取SqlSession的实例,SqlSession提供了在数据库执行SQL命令所需的所有方法,可以通过SqlSession实例来直接执行已映射的SQL语句。
try (SqlSession session = sqlSessionFactory.openSession()) {
BlogMapper mapper = session.getMapper(BlogMapper.class);
Blog blog = mapper.selectBlog(101);
}
四、探究已映射的SQL语句
mybatistigongdesuoyou特性都可以基于XML的映射语言来实现。
下面为一个简单的映射文件的实例(上面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">
<mapper namespace="org.mybatis.example.BlogMapper">
<select id="selectBlog" resultType="Blog">
select * from Blog where id = #{id}
</select>
</mapper>
五、作用域(Scope)和生命周期
SqlSessionFactoryBuilder:一旦创建了SqlSessionFactory,就不再需要,所以他的实例的最佳作用域就是方法作用域(也就是局部方法变量),可创建多个实例,但最好不要一直保留。
SqlSessionFactory:一旦创建在整个应用运行期间一直存在,使用他的最佳实践就是不要重复创建多次。
SqlSession:每个线程都有自己的SqlSession实例,他的最佳作用域就是请求或方法作用域。
映射器实例:映射器时=是一些绑定映射语句的接口。映射器接口的实例是从SqlSession中获得的。虽然从技术层面上讲,任何映射器实例的最大作用域与请求他们的SqlSession相同,但方法作用域才是映射器实例最合适的作用域。也就是说,映射器应该在调用他们的方法中被获取,使用完之后即可丢弃。
配置
属性(properties)
这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置。例如:
<properties resource="org/mybatis/example/config.properties">
<property name="username" value="dev_user"/>
<property name="password" value="F2Fa3!33TYyg"/>
</properties>
设置好的属性可以在整个配置文件中用来替换需要动态配置的属性值。比如:
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
类型别名(typeAliases)
类型别名可为java类型设置一个缩写名字,他仅用于XML配置,例如:
<typeAliases>
<typeAlias alias="Author" type="domain.blog.Author"/>
<typeAlias alias="Blog" type="domain.blog.Blog"/>
<typeAlias alias="Comment" type="domain.blog.Comment"/>
</typeAliases>
当这样配置是,Author可以用在任何使用domain.blog.Author的地方。
也可以指定一个包名,mybatis会在包名下搜索需要的Java Bean,比如:
<typeAliases>
<package name="domain.blog"/>
</typeAliases>
每一个在包domain.blog中的Java Bean,在没有注解的情况下,会使用Bean的首字母小写的非限定类名来作为他的别名。比如domain.blog.Author的别名为author;若有注解,怎别名为其注解值
@Alias("author")
public class Author {
...
}
环境配置(environments)
可以配置多个环境,但每个SqlSessionFactory实例只能选择一种环境,如果想要连接两个数据库,就要创建两个SqlSessionFactory实例
为了指定创建哪种环境,只要将他作为可选参数传递给SqlSessionFactoryBuilder即可。可以接受环境配置的两个方法签名是:
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment);
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment, properties);
此处符合的是上面properties的第二种动态参数。
注意一些关键点:
默认使用的环境ID(比如:default="development")
每个environment元素定义的环境ID(比如:id="development")
事务管理器的配置(比如:type="JDBC")
数据源的配置(比如:type="POOLED")
默认环境和环境ID顾名思义,环境可以任意命名,但务必保证默认的环境ID要匹配其中一个环境ID
事务管理器(transactionManager)
在Mybatis中有两种类型的事务管理器
JDBC:这个配置直接使用了JDBC的提交和回滚设施,他依赖从数据源获得的练级来管理事务作用域。
MANAGED:不提供提交和回滚,而是让容器来管理事务的整个生命周期
(如果是Spring+MyBatis在没必要配置事务管理器,因为Spring模块自带管理器)
数据源(dataSource)
dataSource元素只用标准的JDBC数据源接口来配置JDBC连接对象的资源
UNPOOLED:这个数据源的实现会每次请求时打开或关闭连接
POOLED:这种数据库的实现利用"池"的概念将JDBC连接对象组织起来,避免了创建新的连接实例时所必需的初始化和认证时间
JNDI:这个数据源实现时为了能在如EJB或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个JNDI上下文的数据源引用
映射器(mappers)
mappers用来告诉MyBatis去哪里找到SQL映射语句,映射文件。
<!-- 使用相对于类路径的资源引用 -->
<mappers>
<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
<mapper resource="org/mybatis/builder/BlogMapper.xml"/>
<mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>
<!-- 使用完全限定资源定位符(URL) -->
<mappers>
<mapper url="file:///var/mappers/AuthorMapper.xml"/>
<mapper url="file:///var/mappers/BlogMapper.xml"/>
<mapper url="file:///var/mappers/PostMapper.xml"/>
</mappers>
<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers>
<mapper class="org.mybatis.builder.AuthorMapper"/>
<mapper class="org.mybatis.builder.BlogMapper"/>
<mapper class="org.mybatis.builder.PostMapper"/>
</mappers>
<!-- 将包内的映射器接口实现全部注册为映射器 -->
<mappers>
<package name="org.mybatis.builder"/>
</mappers>
XML映射器
SQL映射文件常用的元素
cache:该命名空间的缓存配置
cache-ref:引用其他命名空间的缓存配置
resultMap:描述如何从数据库结果集中加载对象,是最复杂也是最强大的元素
sql:可被其他语句引用的可重用语句块
insert:映射插入语句
update:映射更新语句
delete:映射删除语句
select:映射查询语句
<insert id="insertAuthor">
insert into Author (id,username,password,email,bio)
values (#{id},#{username},#{password},#{email},#{bio})
</insert>
<update id="updateAuthor">
update Author set
username = #{username},
password = #{password},
email = #{email},
bio = #{bio}
where id = #{id}
</update>
<delete id="deleteAuthor">
delete from Author where id = #{id}
</delete>
1、sql
这个元素可以用来定义可重用的SQL代码片段,以便在其它语句中使用。参数可以静态的确定下来,并且可以在不同的include元素中定义不同的参数值,比如:
<sql id="userColumns"> ${alias}.id,${alias}.username,${alias}.password </sql>
这个sql片段可以在其他语句中使用,例如:
<select id="selectUsers" resultType="map">
select
<include refid="userColumns"><property name="alias" value="t1"/></include>,
<include refid="userColumns"><property name="alias" value="t2"/></include>
from some_table t1
cross join some_table t2
</select>
2、结果映射(resultMap)
ResultMap的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了。
<select id="selectUsers" resultType="map">
select id, username, hashedPassword
from some_table
where id = #{id}
</select>
上述语句只是简单的将所有的列映射到HashMap的键上,这由resultType属性指定。
3、构造方法
构造方法注入允许初始化时为类设置属性的值,而不用暴露出公有方法。
为了将结果注入构造方法,MyBatis需要通过某种方式定位相应的构造方法。weil通过名称来引用构方法参数,可以添加@Param注解。
<constructor>
<idArg column="id" javaType="int" name="id" />
<arg column="age" javaType="_int" name="age" />
<arg column="username" javaType="String" name="username" />
</constructor>
如果存在名称和类型相同的属性,那么javaType可以省略。
动态SQL
动态SQL的重要元素
if
choose(when,otherwrise)
trim(where,set)
foreach
1、if
使用动态SQL最常见情景是根据条件包含where子句的一部分。比如:
<select id="findActiveBlogWithTitleLike"
resultType="Blog">
SELECT * FROM BLOG
WHERE state = ‘ACTIVE’
<if test="title != null">
AND title like #{title}
</if>
</select>
2、choose、when、otherwrise
针对有时只是想从多个选择中选择一个使用这种情况,MyBatis提供了choose,类似于Java的switch语句。
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG WHERE state = ‘ACTIVE’
<choose>
<when test="title != null">
AND title like #{title}
</when>
<when test="author != null and author.name != null">
AND author_name like #{author.name}
</when>
<otherwise>
AND featured = 1
</otherwise>
</choose>
</select>
3、trim、where、set
有些情况会出现语句条件判断后,没有相匹配的,或匹配的是第二个条件,导致SQL语句出错。
SELECT * FROM BLOG
WHERE
SELECT * FROM BLOG
WHERE
AND title like ‘someTitle’
这时只需要改动一处即可解决,也就是where处改动。
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG
<where>
<if test="state != null">
state = #{state}
</if>
<if test="title != null">
AND title like #{title}
</if>
<if test="author != null and author.name != null">
AND author_name like #{author.name}
</if>
</where>
</select>
where元素只会在子元素返回任何内容的情况下才插入where子句,若字句开头为and或or,where元素会将他们去除。
如果where元素合预想不同,也可以通过自定义trim来定制where元素的功能。比如,和where元素等价的自定义trim为:
<trim prefix="WHERE" prefixOverrides="AND |OR ">
...
</trim>
上述AND后的空格是必要的。
用于动态更新语句的类似解决方案叫做set。set元素可以用于动态包含需要更新的列,忽略不更新的列。比如:
<update id="updateAuthorIfNecessary">
update Author
<set>
<if test="username != null">username=#{username},</if>
<if test="password != null">password=#{password},</if>
<if test="email != null">email=#{email},</if>
<if test="bio != null">bio=#{bio}</if>
</set>
where id=#{id}
</update>
与其等价的trim自定义为:
<trim prefix="SET" suffixOverrides=",">
...
</trim>
4、foreach
动态SQL的另一个常见使用场景是对集合进行遍历,尤其是构建IN条件语句的时候,比如:
<select id="selectPostIn" resultType="domain.blog.Post">
SELECT *
FROM POST P
WHERE ID in
<foreach item="item" index="index" collection="list"
open="(" separator="," close=")">
#{item}
</foreach>
</select>
foreach可以指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。也可以指定开头和结尾的字符以及集合项迭代之间的分隔符。
示例
本示例只实现了一个功能,就是在数据库中通过id查询用户信息,若想要实现其他功能,需自己修改。
1、首先在pom文件中添加mybatis依赖:
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
</dependencies>
2、定义mybatis-config文件,确定数据库信息:
<?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>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/lianxi?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="usermapper.xml"/>
</mappers>
</configuration>
3、数据库的user表内容如下:
4、根据user表定义User实体类:
package com.example.pojo;
/**
* 2024/4/29 9:11
*/
public class user {
public int id;
public String name;
public user(int id, String name) {
this.id = id;
this.name = name;
}
@Override
public String toString() {
return "user{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
5、定义UserMapper接口,声明方法:
package com.example.mapper;
import com.example.pojo.user;
public interface usermapper {
user selectById(int id);
}
6、定义UserMapper的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.example.mapper.usermapper">
<select id="selectById" resultType="com.example.pojo.user">
select * from user where id = #{id}
</select>
</mapper>
7、定义启动类,运行方法:
package com.example;
import com.example.mapper.usermapper;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
public class Main {
public static void main(String[] args) throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
try(SqlSession session=sqlSessionFactory.openSession()) {
usermapper mapper = session.getMapper(usermapper.class);
System.out.println(mapper.selectById(1));
}
}
}
8、查询数据库中id为1的用户信息,运行结果:
结束
如此便是MyBatis的主要重点,如果有遗漏,后续会继续补充,如有错误,希望指出。