mybatis是一个优秀的基于java的持久层框架,它内部封装了jdbc,使开发者只需要关注sql语句本身,而不需要花费精力
去处理加载驱动、创建连接、创建statement等繁杂的过程。mybatis通过xml或注解的方式将要执行的各种 statement配置起来,并通过java对象和statement中sql的动态参数进行映射生成最终执行的sql语句。
最后mybatis框架执行sql并将结果映射为java对象并返回。采用ORM思想解决了实体和数据库映射的问题,对jdbc 进行了封装,屏蔽了jdbc api底层访问细节,使我们不用与jdbc api打交道,就可以完成对数据库的持久化操作。
MyBatis官网地址:http://www.mybatis.org/mybatis-3/
MyBatis
的坐标user
数据表User
实体类UserMapper.xml
SqlMapConfig.xml
插入操作注意问题
insert
标签parameterType
属性指定要插入的数据类型Sql
语句中使用#{实体属性名}
方式引用实体中的属性值sqlSession.insert(“命名空间.id”,实体对象);
sqlSession
对象显示的提交事务,即sqlSession.commit()
修改操作注意问题
update
标签sqlSession.update(“命名空间.id”,实体对象);
删除操作注意问题
delete
标签Sql
语句中使用#{任意字符串}
方式引用传递的单个参数sqlSession.delete(“命名空间.id”,Object)
核心配置文件层级关系
其中,事务管理器(transactionManager)类型有两种:
其中,数据源(dataSource)类型有三种:
该标签的作用是加载映射的,加载方式有如下几种:
实际开发中,习惯将数据源的配置信息单独抽取成一个properties
文件,该标签可以加载额外配置的properties
文件
类型别名是为Java 类型设置一个短的名字。
【例】原来的类型名称配置如下:
<select id="findAll" resultType="one.wangyi.domain.User">
select * from User
select>
配置typeAliases
,为one.wangyi.domain.User
定义别名为user
:
<typeAliases>
<typeAlias type="com.itheima.domain.User" alias="user">typeAlias>
typeAliases>
配置别名后就可以使用了:
<select id="findAll" resultType="user">
select * from User
select>
上面我们是自定义的别名,mybatis
框架已经为我们设置好的一些常用的类型的别名:
别名 | 数据类型 |
---|---|
string | String |
long | Long |
int | Integer |
double | Double |
boolean | Boolean |
…… | …… |
通过加载mybatis
的核心文件的输入流的形式构建一个SqlSessionFactory
对象
String resource = "org/mybatis/builder/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(inputStream);
其中, Resources
工具类,这个类在 org.apache.ibatis.io
包中。Resources
类帮助你从类路径下、文件系统或一个 web URL
中加载资源文件
SqlSessionFactory
有多个个方法创建 SqlSession
实例。常用的有如下两个:
方法 | 解释 |
---|---|
openSession() | 会默认开启一个事务,但事务不会自动提交,也就意味着需要手动提 交该事务,更新操作数据才会持久化到数据库中 |
openSession(boolean autoCommit) | 参数为是否自动提交,如果设置为true,那么不需要手动提交事 |
SqlSession
实例在 MyBatis
中是非常强大的一个类。能看到所有执行语句、提交或回滚事务和获取映射器实例的方法。
执行语句的方法主要有:
<T> T selectOne(String statement, Object parameter)
<E> List<E> selectList(String statement, Object parameter)
int insert(String statement, Object parameter)
int update(String statement, Object parameter)
int delete(String statement, Object parameter)
操作事务的方法主要有:
void commit()
void rollback()
项目中有dao层接口类及其实现类,将mybatis代码写入dao层实现类的方法中,在service层调用dao层实现类中的方法获得数据库中数据
采用 Mybatis 的代理开发方式实现 DAO 层的开发,这种方式是企业的主流。
Mapper 接口开发方法只需要程序员编写 Mapper 接口(相当于Dao接口),由Mybatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。
Mapper 接口开发需要遵循以下规范:
代理方式对Dao进行实现:
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
MyBatis映射文件配置:
:查询
:插入
:修改
:删除
:where条件
:if判断
:循环
:sql片段抽取Mybatis 的映射文件中,前面我们的 SQL 都是比较简单的,有些时候业务逻辑复杂时,我们的 SQL是动态变化的,此时在前面的学习中我们的 SQL 就不能满足要求了。
参考的官方文档,描述如下:
我们根据实体类的不同取值,使用不同的 SQL语句来进行查询。比如在 id如果不为空时可以根据id查询,如果 username 不同空时还要加入用户名作为条件。这种情况在我们的多条件组合查询中经常会碰到。
<select id="findByCondition" parameterType="User" resultType="user">
select * from user
<where>
<if test="id!=0">
and id = #{id}
if>
<if test="username!=null">
and username = #{username}
if>
<if test="password!=null">
and password = #{password}
if>
where>
select>
循环执行sql的拼接操作,例如:SELECT * FROM USER WHERE id IN (1,2,5)
<select id="findByIds" parameterType="list" resultType="user">
select * from user
<where>
<foreach collection="list" open="id in(" close=")" item="id" separator=",">
#{id}
foreach>
where>
select>
标签用于遍历集合,它的属性:
Sql 中可将重复的 sql 提取出来,使用时用
引用即可,最终达到 sql 重用的目的
<sql id="selectUser">select * from usersql>
<select id="findByCondition" parameterType="User" resultType="user">
<include refid="selectUser"/>
<where>
<if test="id!=0">
and id = #{id}
if>
<if test="username!=null">
and username = #{username}
if>
<if test="password!=null">
and password = #{password}
if>
where>
select>
MyBatis核心配置文件常用标签:
properties
标签:该标签可以加载外部的properties
文件typeAliases
标签:设置类型别名environments
标签:数据源环境配置标签typeHandlers
标签:配置自定义类型处理器plugins
标签:配置MyBatis的插件无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时, 都会用类型处理器将获取的值以合适的方式转换成 Java 类型。下表描述了一些默认的类型处理器(截取部分):
可以重写类型处理器或创建自己的类型处理器来处理不支持的或非标准的类型。具体做法为:实现org.apache.ibatis.type.TypeHandler
接口, 或继承一个很便利的类org.apache.ibatis.type.BaseTypeHandler
, 然 后可以选择性地将它映射到一个JDBC类型。
例如需求:一个Java中的Date
数据类型,想将之存到数据库的时候存成一个1970年至今的毫秒数,取出来时转换成java的Date
,即java的Date
与数据库的bigint
毫秒值之间转换。
开发步骤:
BaseTypeHandler
setNonNullParameter
为java程序设置数据到数据库的回调方法,getNullableResult
为查询时 mysql的字符串类型转换成 java的Type类型的方法MyBatis可以使用第三方的插件来对功能进行扩展。
分页助手PageHelper
是将分页的复杂操作进行封装,使用简单的方式即可获得分页的相关数据
开发步骤:
用户表和订单表的关系为,一个用户有多个订单,一个订单只从属于一个用户
一对一查询的需求:查询一个订单,与此同时查询出该订单所属的用户
对应的sql语句:
SELECT * FROM orders,user where orders.uid=user.id;
查询的结果如下:
创建Order和User实体:
创建OrderMapper接口:
public interface OrderMapper {
List<Order> findAll();
}
配置OrderMapper.xml:
<mapper namespace="one.wangyi.mapper.OrderMapper">
<resultMap id="orderMap" type="order">
<id column="id" property="id">id>
<result column="ordertime" property="ordertime">result>
<result column="total" property="total">result>
<result column="uid" property="user.id">result>-->
<result column="username" property="user.username">result>-->
<result column="password" property="user.password">result>-->
<result column="birthday" property="user.birthday">result>-->
resultMap>
<select id="findAll" resultMap="orderMap">
SELECT * FROM orders,user where orders.uid=user.id
select>
mapper>
其中还可以配置如下:
<resultMap id="orderMap" type="order">
<id column="id" property="id">id>
<result column="ordertime" property="ordertime">result>
<result column="total" property="total">result>
<association property="user" javaType="user">
<id column="id" property="id">id>
<result column="username" property="username">result>
<result column="password" property="password">result>
<result column="birthday" property="birthday">result>
association>
resultMap>
// 获得MyBatis框架生成的OrderMapper接口的实现类
OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);
List<Order> orderList = mapper.findAll();
for (Order order:orderList){
System.out.println(order);
}
用户表和订单表的关系为,一个用户有多个订单,一个订单只从属于一个用户
一对多查询的需求:查询一个用户,与此同时查询出该用户具有的订单
对应的sql语句:
SELECT * FROM user,orders WHERE user.id=orders.uid;
查询的结果如下:
创建UserMapper接口:
public interface UserMapper {
List<User> findAll();
}
配置UserMapper.xml:
<mapper namespace="one.wangyi.mapper.UserMapper">
<resultMap id="userMap" type="user">
<id column="id" property="id">id>
<result column="username" property="username">result>
<result column="password" property="password">result>
<result column="birthday" property="birthday">result>
<collection property="orderList" ofType="order">
<id column="id(1)" property="id">id>
<result column="ordertime" property="ordertime">result>
<result column="total" property="total">result>
collection>
resultMap>
<select id="findAll" resultMap="userMap">
SELECT *FROM user,orders WHERE user.id=orders.uid
select>
mapper>
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = mapper.findAll();
for (User user:userList) {
System.out.println(user);
}
用户表和角色表的关系为,一个用户有多个角色,一个角色被多个用户使用
多对多查询的需求:查询用户同时查询出该用户的所有角色
对应的sql语句:
select * from user,user_role,role where user.id=user_role.user_id AND user_role.role_id=role.id;
查询结果如下:
创建Role实体,修改User实体:
添加UserMapper接口方法:
public interface UserMapper {
public List<User> findAll();
public List<User> findUserAndRoleAll();
}
配置UserMapper.xml:
<mapper>
<resultMap id="userRoleMap" type="user">
<id column="id" property="id">id>
<result column="username" property="username">result>
<result column="password" property="password">result>
<result column="birthday" property="birthday">result>
<collection property="roleList" ofType="role">
<id column="role_Id" property="id">id>
<result column="roleName" property="roleName">result>
collection>
resultMap>
<select id="findUserAndRoleAll" resultMap="userRoleMap">
select * from user,user_role,role where user.id=user_role.user_id AND user_role.role_id=role.id
select>
mapper>
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> userAndRoleAll = mapper.findUserAndRoleAll();
for (User user : userAndRoleAll) {
System.out.println(user);
}
MyBatis多表配置方式:
做配置+
做配置+
做配置Mybatis可以使用注解开发方式,这样就可以减少编写Mapper映射文件了
@Insert
:实现新增@Update
:实现更新@Delete
:实现删除@Select
:实现查询@Result
:实现结果集封装@Results
:可以与@Result
一起使用,封装多个结果集@One
:实现一对一结果集封装@Many
:实现一对多结果集封装修改MyBatis的核心配置文件,因为使用了注解来替代映射文件,所以只需要加载使用了注解的Mapper接口即可
<mappers>
<mapper class="one.wangyi.mapper.UserMapper">mapper>
mappers>
或者指定扫描含映射关系的接口所在的包也可以
<mappers>
<package name="one.wangyi.mapper">package>
mappers>
之前我们可以在映射文件中通过配置
来实现复杂关系映射,在使用注解开发后,我们可以使用@Results
注解 ,@Result
注解,@One
注解,@Many
注解组合完成复杂关系的配置。
@Results
:代替的是标签
,该注解中可以使用单个@Result
注解,也可以使用@Result
集合。使用格式:@Results( { @Result(), @Result() } )
或@Results( @Result() )
@Result
:代替了
标签和
标签,@Result
中属性介绍:
column
:数据库的列名property
:需要装配的属性名one
:需要使用的@One
注解@Result ( one=@One( ) )
many
:需要使用的@Many
注解@Result ( many=@Many( ) )
One(一对一)
:代替了
标签,是多表查询的关键,在注解中用来指定子查询返回单一对象。
select
:指定用来多表查询的 sqlmapper
@Result(column=" ",property="",one=@One(select=""))
Many(多对一)
:代替了
标签, 是多表查询的关键,在注解中用来指定子查询返回对象集合。
@Result(property="",column="",many=@Many(select=""))
查询一个订单,与此同时查询出该订单所属的用户
对应的sql语句:
select * from orders;
select * from user where id=查询出的订单的uid;
创建Order和User实体类同上xml方式,这里不再赘述
使用注解配置OrderMapper和UserMapper接口类:
@Test
public void testOneToOne(){
List<Order> all = mapper.findAll();
for (Order order : all) {
System.out.println(order);
}
}
查询一个用户,与此同时查询出该用户具有的订单
对应的sql语句:
select * from user;
select * from orders where uid=查询出的用户的id;
修改User实体类同上xml方式,这里不再赘述
使用注解配置UserMapper和OrderMapper接口类:
@Test
public void testOneToMany(){
List<User> userAndOrderAll = mapper.findUserAndOrderAll();
for (User user : userAndOrderAll) {
System.out.println(user);
}
}
查询用户同时查询出该用户的所有角色
对应的sql语句:
select * from user;
SELECT * from user_role ,role where user_role.role_id=role.id and user_role.user_id=用户的id
创建Role实体类,修改User实体类同上xml方式,这里不再赘述
使用注解配置UserMapper和RoleMapper接口类:
@Test
public void testManyToMany(){
List<User> userAndRoleAll = mapper.findUserAndRoleAll();
for (User user : userAndRoleAll) {
System.out.println(user);
}
}