Mybatis介绍
Mybatis简单使用
-
初始化SqlSessionFactory对象
SqlSessionFactory对象需要从一个核心配置文件中构建,因此我们创建SqlSessionFactory对象之前需要先配置一个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> <!-- 引入外部properties文件,路径从类路径的根目录开始 --> <properties resource="jdbc.properties" /> <settings> <!-- 开启将数据库中下划线连接的字段自动映射为Java的小驼峰命名 --> <setting name="mapUnderscoreToCamelCase" value="true"/> </settings> <!-- 定义类型别名,在xxxMapper.xml文件中就可以用别名代替很长的类名 --> <typeAliases> <!-- 单个类配置别名 --> <!-- <typeAlias type="com.lanou3g.mybatis.bean.User" alias="User" />--> <!-- 统一配置某个包下所有类的别名, 会使用 Bean 的首字母小写的类名来作为它的别名。 --> <package name="com.lanou3g.mybatis.bean" /> </typeAliases> <!-- 配置不同环境的参数 --> <environments default="development"> <!-- 开发环境数据库、事务配置 --> <environment id="development"> <!-- 事务管理使用JDBC的事务 --> <transactionManager type="JDBC"/> <!-- 配置开发环境数据源 --> <dataSource type="POOLED"> <property name="driver" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.user}"/> <property name="password" value="${jdbc.password}"/> <!-- 将所有driver.开头的参数,附加到url属性的值后面上 --> <property name="driver.characterEncoding" value="utf8"/> </dataSource> </environment> </environments> <!-- 将mapper SQL映射文件包含进来 --> <mappers> <!-- 将通过XML方式配置的mapper引入进来 --> <mapper resource="mapper/userMapper.xml"/> <!-- 将通过注解方式配置的mapper引入进来 --> <!-- <mapper class="com.lanou3g.mybatis.mapper.UserMapper" />--> <!-- 将com.lanou3g.mybatis.mapper包下所有通过注解方式配置的mapper引入进来 --> <!-- <package name="com.lanou3g.mybatis.mapper"/>--> </mappers> </configuration>
构建对象
// 1. 初始化mybatis配置 String confPath = "mybatis_conf.xml"; InputStream in = Resources.getResourceAsStream(confPath); // 2. 构建SqlSessionFactory对象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
-
创建SqlSession对象
通过上一步的SqlSessionFactory对象可以获取到负责执行SQL语句的SqlSession对象
// 3. 获取SqlSession对象,默认事务不自动提交 // SqlSession sqlSession = sqlSessionFactory.openSession(); // 获取一个自动提交事务的sqlSession SqlSession sqlSession = sqlSessionFactory.openSession(true);
-
用SqlSession对象从Mybatis中获取Mapper接口的实现类
// 4. 获取Mapper UserMapper mapper = sqlSession.getMapper(UserMapper.class);
-
编写Mapper对象的xml配置文件
XML格式的Mapper配置文件类似于接口的实现类,它指定了具体要执行的SQL语句,以及结果集如何映射。
<?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.lanou3g.mybatis.mapper.UserMapper"> <select id="queryAllUser" resultType="user"> select * from user </select> <insert id="insertUser"> insert into user (username,nick_name,email) values (#{username},#{nickName},#{email}) </insert> </mapper>
深入了解Mybatis
主要组件
核心配置文件
核心配置文件是Mybatis的入口,它里面可以配置mybatis的具体参数、数据源、类型别名、关联映射文件等。。
具体的参数配置说明参见:
SqlSessionFactory
一个SqlSessionFactory只能连接一个数据库实例,如果需要连接多个数据库,需要构建多个SqlSessionFactory对象。
在构建SqlSesssionFactory时可以指定environment的id,表示使用指定的数据源来构建factory对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in, "dev");
SqlSession
一个SqlSession对象代表一次到数据的会话,该对象有一下功能:
- 获取Mapper实现类
- 管理事务操作
注意: SqlSession对象是非线程安全的,在多线程环境下,建议不要作为类的实例属性来用。
Mapper
-
Mapper接口类
定义了增删盖查的方法。注意,必须是接口类型,而且方法只需要定义就可以了。
-
Mapper配置文件
Mapper配置文件中就是负责实现接口中的方法,它定义了具体要执行什么SQL语句,如何映射结果集。
- 配置文件中select、delete、update、insert标签的id必须是对应接口中的方法名。
- mapper文件的namespace属性需要对应Mapper接口的完全类型限定名。
深入Mybatis核心配置文件
具体的参数配置说明参见:
深入Mybatis映射配置文件
CRUD语句定义
查询语句
接口中
List<User> queryAllUser();
User queryUserById(Integer id);
xml配置文件中
<select id="queryAllUser" resultType="user">
select * from user
</select>
<select id="queryUserById" resultType="user">
select * from user where id = #{id}
</select>
插入语句
普通插入语句
接口中
int insertUser(User user);
xml配置文件中
<insert id="insertUser">
insert into user (username,nick_name,email)
values (#{username},#{nickName},#{email})
</insert>
如何返回数据库自增的ID
<!-- 给insert语句添加useGeneratedKeys、keyProperty后,mybatis会将自增的id值直接赋值到传进来的user对象的id属性上
useGeneratedKeys: 指定需要获取数据库自增的id
keyProperty: 指定自增地段的名称
-->
<insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
insert into user (username,nick_name,email)
values (#{username},#{nickName},#{email})
</insert>
删除语句
接口中
void deleteUserById(Integer id);
XML配置中
<delete id="deleteUserById">
delete from user where id = #{id}
</delete>
更新语句
接口中
void updateUser(User user);
XML配置中
<update id="updateUser">
update user set password = #{password} where id = #{id}
</update>
接口中的参数如果传递到SQL中
简单类型参数
接口中:
void deleteUserById(Integer id);
xml配置文件中:
<delete id="deleteUserById">
delete from user where id = #{id}
</delete>
引用类型参数
接口中:
int insertUser(User user);
xml配置文件中:
<!-- 给insert语句添加useGeneratedKeys、keyProperty后,mybatis会将自增的id值直接赋值到传进来的user对象的id属性上
useGeneratedKeys: 指定需要获取数据库自增的id
keyProperty: 指定自增地段的名称
-->
<insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
insert into user (username,nick_name,email)
values (#{username},#{nickName},#{email})
</insert>
当接口中参数和XML配置取值时名称不一样时
在接口中的参数前加注解
User queryUserById(@Param("id") Integer xxxxxxxId);
在XML中取值时用注解指定的名称
<select id="queryUserById" resultType="user">
select * from user where id = #{id}
</select>
#{}与${}的区别
- 它俩都可以获取接口调用中传递过来的参数
- #{}会将参数作为占位符,使用预编译语句(PreparedStatement)执行
- 会 直 接 用 实 际 参 数 替 换 {}会直接用实际参数替换 会直接用实际参数替换{}, 参数可以作为SQL的一部分。
比如,要实现下面的效果:
Java代码
List<User> queryAllUserOrderBy(String order);
// 调用:
mapper.queryAllUserOrderBy("last_login_time");
XML配置:
<select id="queryAllUserOrderBy" resultMap="userMap">
select * from user order by ${order} desc;
</select>
如果上面使用#{order}取获取参数,最终执行的SQL会是这样:
==> Preparing: select * from user order by ? desc;
==> Parameters: last_login_time(String)
无法实现排序效果
如果使用${order}来取参数,最终执行SQL:
==> Preparing: select * from user order by last_login_time desc;
==> Parameters:
可以实现排序效果
结果集如何映射
ResultType方式
ResultType方式适用于数据库结果集可以直接映射成一个Java类的情况
Java实体类:
@Getter
@Setter
@ToString
public class User {
private Integer id;
private String username;
private String nickName;
private String password;
private String email;
private Timestamp lastLoginTime;
}
使用方法:
<select id="queryAllUser" resultType="com.lanou3g.bean.User">
select * from user
</select>
ResultMap方式
ResultMap方式适用于复杂的结果集映射,比如数据库返回的结果集中的列名和JavaBean无法一一对应,或者对象间存在一对一、一对多关联映射时。
解决数据库列名与Java类中属性名不一致的映射问题
<mapper>
...
<resultMap id="userMap" type="user">
<id property="id" column="id" />
<result property="username" column="username" />
<result property="lastLoginttime" column="last_login_time" />
<result property="email" column="email" />
<result property="nickName" column="nick_name" />
</resultMap>
...
</mapper>
在查询语句中将resultType换成resultMap
<select id="queryAllUser" resultMap="userMap">
select * from user
</select>
其实,如果遇到单纯字段名和属性名不对应的情况,使用别名的方式更简单
解决一对一映射查询问题
解决一对多映射查询问题
动态SQL
条件分支SQL
- if
- choose&when&otherwise
循环SQL
- forEach
其他特殊SQL
- where
- set
- trim
批量插入
通过forEach动态SQL方式
通过Executor.BATCH的方式
缓存
一级缓存(本地缓存)
二级缓存(全局缓存)
Mybatis逆向工程
Spring与Mybatis整合
-
加入依赖
<!-- mybatis-spring整合依赖,这个是最主要的一个依赖 --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>2.0.1</version> </dependency> <!-- Spring和数据源相关依赖 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.0.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.2.0.RELEASE</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.20</version> </dependency>
-
在Spring bean配置文件中配置Mybatis、Spring整合bean SqlSessionFactoryBean
<!-- 配置整合bean --> <bean id="sessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean"> <!-- 数据源是必要参数 --> <property name="dataSource" ref="dataSource" /> <!-- Mybatis核心配置文件其实大多数情况下都可以省略,通过指定属性可以间接设置核心配置文件中的参数 --> <!--<property name="configLocation" value="mybatis_conf.xml" />--> <!-- 省略mybatis核心配置文件后,可以通过类似下面这些特定属性,设置mybatis参数 --> <property name="typeAliasesPackage" value="com.lanou3g.mybatis.spring.bean" /> <property name="mapperLocations" value="classpath:mapper/*.xml" /> </bean>
-
在Spring bean配置文件中开启Mybatis Mapper扫描
-
需要使用mybatis schema
配置方法,在bean配置文件的头部添加
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:mybatis="http://mybatis.org/schema/mybatis-spring" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring.xsd">
-
开启Mybatis Mapper扫描
开启Mybatis Mapper扫描的作用是:告诉Mybatis要创建哪个包下接口的实现类,并以bean的方式加入到SpringIOC容器中
<!-- 开启Mapper扫描,Mybatis会创建将此包下的接口的实现类,并以bean的方式加入到SpringIOC容器中 --> <mybatis:scan base-package="com.lanou3g.mybatis.spring.mapper" />
-
-
创建实体类、mapper映射文件、Mapper接口(可以通过Mybatis逆向工程直接生成)
Mapper接口
@Repository //此注解不是必须的,因为MessageMapper类的实现类是由Mybatis创建并放到ioc容器中的,不是由Spring来创建的。 public interface MessageMapper { int insert(Message record); List<Message> selectAll(); }
实体类、映射文件 略
-
将Mapper接口用Spring自动注入的方式注入到需要的地方使用
MessageService.java
@Service public class MessageService { @Autowired MessageMapper messageMapper; public List<Message> queryAllMessage() { return messageMapper.selectAll(); } }