mybatis从入门到精通
发布时间:2018-07-01 08:42:14
发布时间:2018-07-01 08:42:14
1、对原生态的jdbc程序问题总结
1.1 jdbc程序:使用jdbc查询mysql数据库中用户表的记录
1.2 问题:
1)数据库连接使用时创建、不使用时就释放:对数据库进行频繁的连接的创建和释放,造成数据库资源浪费,影响数据库性能---------------使用数据库连接池管理数据库连接
2)将sql语句硬编码到java代码中,如果sql语句修改,需要重新编译java代码,不利于系统维护-------------将sql语句配置在xml配置文件中,即使sql变化,不需要对java代码进行重新编译
3)向prepareStatement中设置参数,对占位符号位置和设置参数值,硬编码在java代码中,不利于系统维护-------------------将sql语句及占位符和参数全部配置在xml文件中
4)从resultSet中遍历结果集数据时,存在硬编码,将获取表的字段进行硬编码,不利于系统维护----------------------将结果集自动映射成java对象
2、mybatis框架原理
2.1 mybatis是什么?
mybatis是一个持久层框架,是apache下的顶级项目
github下:https://github.com/mybatis/mybatis-3/releases
mybatis让程序员将主要精力放在sql上,通过mybatis提供的映射方式,自由灵活生成满足sql需要的sql语句
mybatis可以将向preparestatement输入的参数自动进行输入映射,将查询结果集灵活映射成java对象(输出映射)。
2.2 mybatis框架
\
3、mybatis入门程序
3.1 需求
根据主键查询用户信息
根据用户名模糊查询用户信息
怎删改查.....
3.2 mybati运行环境(jar包):
从https://github.com/mybatis/mybatis-3/releases 下载
lib下:依赖包
mybatis-3.4.1.jar:核心包
3.3 log4j.properties
#Global logging configuration
log4j.rootLogger=ERROR, stdout
#MyBatis logging configuration...
log4j.logger.org.mybatis.example.BlogMapper=TRACE
#Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p[%t]-%m%n
3.4 工程目录结构
3.5 根据用户id查询用户信息、通过用户名模糊查询用户信息
3.5.1 编写映射文件(包括对应的实体类:User.java)
映射文件命名:User.xml(原始的ibatis命名方式),mapper代理的映射文件名称叫做XXXMapper.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="test">
<select id="findUserById" parameterType="int" resultType="com.liyuan.po.User">
SELECT * FROM USER WHERE uid=#{id}
select>
<select id="findUserByName" parameterType="java.lang.String" resultType="com.liyuan.po.User">
SELECT * FROM USER WHERE name LIKE '%${value}%'
select>
mapper>
3.5.2 将映射文件加载到SqlMapConfig配置文件中
<mappers>
<mapper resource="sqlmap/User.xml"/>
mappers>
3.5.3 程序编写
@Test
publicvoid findUserByIdTest()throwsIOException{
// mybatis配置文件
String resource ="SqlMapConfig.xml";
InputStream input =Resources.getResourceAsStream(resource);
// 创建会话工厂
SqlSessionFactory sqlSessionFactory =newSqlSessionFactoryBuilder()
.build(input);
// 通过工厂得到SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 通过SqlSession操作数据库
User user = sqlSession.selectOne("test.findUserById",23);
System.out.println(user.getName());
// 释放资源
sqlSession.close();
}
// 根据name查询用户信息,得到一条记录的结果
@Test
publicvoid findUserByNameTest()throwsIOException{
// mybatis配置文件
String resource ="SqlMapConfig.xml";
InputStream input =Resources.getResourceAsStream(resource);
// 创建会话工厂
SqlSessionFactory sqlSessionFactory =newSqlSessionFactoryBuilder()
.build(input);
// 通过工厂得到SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 通过SqlSession操作数据库
List<User> list = sqlSession.selectList("test.findUserByName","李");
System.out.println(list.size());
// 释放资源
sqlSession.close();
}
3.6 插入用户信息
3.6.1 User.xml映射文件:
<insert id="insertUser" parameterType="com.liyuan.po.User">
insert into user(username,password) value(#{username},#{password})
insert>
3.6.2 测试代码:
@Test
publicvoid insertUserTest()throwsIOException{
// mybatis配置文件
String resource ="SqlMapConfig.xml";
InputStream input =Resources.getResourceAsStream(resource);
// 创建会话工厂
SqlSessionFactory sqlSessionFactory =newSqlSessionFactoryBuilder()
.build(input);
// 通过工厂得到SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 通过SqlSession操作数据库
User user =newUser();
user.setUsername("ll");
user.setPassword("123456");
sqlSession.insert("test.insertUser",user);
//提交事务
sqlSession.commit();
// 释放资源
sqlSession.close();
}
3.7 自增主键返回
mysql自增主键,执行insert提交之前自动生成一个自增主键。
通过mysql函数获取到刚刚插入的记录的自增主键 last_insert_id() ,是在insert之后调用此函数
3.7.1 User.xml映射文件配置:
<insert id="insertUser" parameterType="com.liyuan.po.User">
<selectKey keyProperty="uid" order="AFTER" resultType="java.lang.Integer">
SELECT LAST_INSERT_ID()
selectKey>
insert into user(username,password) value(#{username},#{password})
insert>
3.7.2 程序代码中直接获取
@Test
publicvoid insertUserTest()throwsIOException{
// mybatis配置文件
String resource ="SqlMapConfig.xml";
InputStream input =Resources.getResourceAsStream(resource);
// 创建会话工厂
SqlSessionFactory sqlSessionFactory =newSqlSessionFactoryBuilder()
.build(input);
// 通过工厂得到SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 通过SqlSession操作数据库
User user =newUser();
user.setUsername("ll");
user.setPassword("123456");
sqlSession.insert("test.insertUser",user);
//提交事务
sqlSession.commit();
System.out.println(user.getUid());
// 释放资源
sqlSession.close();
}
3.8 非自增主键的返回
使用mysql的uuid()函数生成主键,需要修改表中uid字段类型为string,长度为35
执行的思路:
先通过uuid()查询到主键,将主键输入到sql语句中
执行uuid语句的顺序相对于insert语句之前
<selectKey keyProperty="uid" order="BEFORE" resultType="java.lang.Integer">
SELECT uuid()
selectKey>
insert into user(uid,username,password) value(#{uid},#{username},#{password})
3.9 删除和更新用户
<delete id="deleteUser" parameterType="java.lang.Integer">
delete from user where uid =#{id}
delete>
<update id="updateUser" parameterType="com.liyuan.po.User">
update user set username=#{username},password=#{password} where uid=#{uid}
update>
3.10 #{}和${}
3.11 mybatis和hibernate的区别
hibernate:是一个标准的ORM框架(对象关系映射)。不需要写sql,都是自动生成的。对sql语句进行优化、修改比较困难
适用于需求变化不多的中小型项目,比如:后台管理项目
mybatis:专注是sql本身,在映射文件中需要程序员自己编写sql语句,优化比较方便。mybatis是一个不完全的ORm框架;虽然程序员自己写sql,也可以实现映射(输入、输出映射)。
适用于需求变化较多的项目,比如:互联网项目。
4、mybatis开发dao两种方法:
1)原始dao开发方法(程序需要编写dao接口和dao实现类)
2)mybatis的mapper接口(相当于dao接口)代理开发方法
4.1 SqlSession使用范围
// mybatis配置文件
String resource ="SqlMapConfig.xml";
InputStream input =Resources.getResourceAsStream(resource);
// 创建会话工厂
SqlSessionFactory sqlSessionFactory =newSqlSessionFactoryBuilder().build(input);
// 通过工厂得到SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
4.1.1 通过SqlSessionFactoryBuilder创建会话工厂SqlSessionFactory
4.1.2 通过SqlSessionFactory创建SqlSession,使用单例模式管理sqlsessionFactory
4.1.3 sqlSession是一个面向用户的接口:SqlSession中提供了很多操作数据库的方法;是线程不安全的;Sqlsession最佳适用场合在方法体内,定义成局部变量使用。
4.2 原始dao的开发方法(程序员需要写dao接口和dao实现类)
4.2.1 程序员需要向dao实现类中注入SqlSessionFactory
UserDao接口:定义方法(抛异常)
UserDaoImpl类:实现接口UserDao,并通过构造函数的方法向UserDaoImpl类注入SqlSessionFactory;
UserDaoImplTest类:创建SqlSessionFactory实例,在创建UserDao对象
4.2.2 总结原始dao开发问题
1)dao接口实现类方法中存在大量模板代码,设想能否将这些代码提取出来,大大减少程序员的工作量
2)调用sqlSession的方法时将statement的id硬编码了
3)调用sqlSession的方法时传入的变量,由于sqlSession方法使用泛型,即使变量传入错误,在编译阶段也不会报错
4.3 mapper代理方法(程序员只需要mapper接口[相当于dao接口])
思路:
4.3.1 程序员还需要编写mapper.xml映射文件
4.3.2 程序员编写mapper.java接口需要遵循一些开发规范,mtbatis可以自动生成mapper接口实现类代理对象
开发规范:
1)在mapper.xml中namespace等于mapper接口地址
<mapper namespace="com.liyuan.mapper.UserMapper">
2)mapper.java接口中的方法名和mapper.xml中statement的id一致
3)mapper.java接口中的方法输入参数类型和mapper.xml中statement的parameterType指定的类型一致
4)mapper.java接口中的方法返回值的类型和mapper.xml中statement的resultType指定的类型一致
// 根据用户id查询用户信息
publicUser findUserById(int uid)throwsException;
<select id="findUserById" parameterType="int" resultType="com.liyuan.po.User">
SELECT * FROM USER WHERE uid=#{id}
select>
总结:以上开发规范主要对下边的代码进行统一生成,
User user = sqlSession.selectOne("test.findUserById", uid);
4.3.4 最后还要将mapper.xml映射文件添加到SqlMapConfig.xml配置文件中
<mappers>
<mapper resource="sqlmap/User.xml"/>
<mapper resource="mapper/UserMapper.xml"/>
mappers>
5、mybatis配置文件SqlMapConfig.xml
mybatis的全局配置文件SqlMapConfig.xml。配置内容如下:
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.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/shop"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
dataSource>
environment>
environments>
<!--加载映射文件-->
<mappers>
<mapper resource="sqlmap/User.xml"/>
<mapper resource="mapper/UserMapper.xml"/>
mappers>
configuration>
5.1 properties属性
需求:将数据库的连接参数单独配置在db.properties中,只需在SqlMapConfig.xml中加载db.properties的属性值
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/shop
jdbc.username=root
jdbc.password=123456
注意:mybatis将按照下面的顺序来加载属性:
properties特性:
◇在properties元素体内定义的属性首先被读取
◇然后读取properties元素中resource或url加载的属性,它会覆盖已加载的同名属性
◇最后都去parameterType传递的属性,它会覆盖已读取得同名属性
建议:不要在properties元素体内定义任何属性;在properties属性文件中定义的属性名一定要有特殊性
5.2 settings全局参数配置
mybatis框架在运行时可以调整的一些运行参数。
比如:开启二级缓存、开启延迟加载...
5.3 typeAliases(别名)----重点
需求:在mapper.xml中,定义了很多statement,statement需要parameterType指定输入参数的类型、需要resultType指定输出结果的映射类型。
如果在指定类型是输入类型全路径,不方便进行开发,可以针对parameterType、resultType定义别名,方便开发
5.3.1 自定义别名:
<typeAliases>
<typeAlias type="com.liyuan.po.User" alias="user"/>
<package name="com.liyuan.po"/>
typeAliases>
5.4 typeHandlers(类型处理器)
mybatis中通过typeHandlers完成jdbc类型和java类型的转化----------mybatis提供的默认的类型处理器就够用了,不需要自己定义了
5.5 mappers加载映射文件
<mappers>
<mapper resource="sqlmap/User.xml"/>
<mapper resource="mapper/UserMapper.xml"/>
<!--通过mapper接口加载映射文件
遵循一些规范:需要将mapper接口的类名和mapper.xml映射文件名称保持一致,且在一个目录中-->
<mapper class="com.liyuan.mapper.UserMapper"/>
<package name="com.liyuan.mapper">
package>
mappers>
6、mybatis核心:mybatis输入映射、mybatis输出映射
6.1 输入映射
通过parameterType指定输入参数的类型
6.6.1 传递pojo的包装对象
需求:完成用户信息的综合查询,需要传入查询条件(可能包括用户信息、其他信息)
针对上述需求,建议使用自定义的包装类型pojo,在包装类中将复杂的查询条件包装进去
1)首先,自定义包装类型UserQueryVo.java,里面包装了所有的查询条件
package com.liyuan.po;
publicclassUserQueryVo{
//在这里包装所需要的查询条件
//用户查询条件
privateUserCustom userCustom;
//模糊查询username匹配条件
privateString username;
publicString getUsername(){
return username;
}
publicvoid setUsername(String username){
this.username = username;
}
publicUserCustom getUserCustom(){
return userCustom;
}
publicvoid setUserCustom(UserCustom userCustom){
this.userCustom = userCustom;
}
}
2)其次,为该包装类编写mapper.xml映射文件
<select id="findUserList" parameterType="com.liyuan.po.UserQueryVo" resultType="com.liyuan.po.UserCustom">
select * from user where user.uid=#{userCustom.uid} and user.username like '%${username}%'}
select>
在UserMapper.xml中定义用户信息综合查询(查询条件复杂,通过高级查询)
3)编写mapper.java接口
//用户信息的综合查询
publicList<UserCustom> findUserList(UserQueryVo userQueryVo)throwsException;
4)测试类进行测试
@Test
publicvoid testFindUseList()throwsException{
SqlSession sqlSession = sqlSessionFactory.openSession();
//创建Usermapper对象,mybatis自定生成mapper代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//创建包装对象
UserQueryVo userQueryVo =newUserQueryVo();
UserCustom userCustom =newUserCustom();
userCustom.setUid(25);
userQueryVo.setUserCustom(userCustom);
userQueryVo.setUsername("yao");
//调用UserDao的方法
List<UserCustom> list = userMapper.findUserList(userQueryVo);
System.out.println(list.size());
}
6.2 输出映射
两种方式:
6.2.1 resultType
使用resultType进行输出映射时,只有查询出来的列名和pojo的属性名一致,该列才可以映射成功
如果全部不一致,则不会生成结果对象;只要有一个一致,就会创建pojo对象。
输出简单类型-----例如:用户信息的综合查询列表总数,通过查询总数和上边用户综合查询列表才可以实现分页
1)mapper.xml
<select id="findUserList" parameterType="com.liyuan.po.UserQueryVo" resultType="com.liyuan.po.UserCustom">
select * from user where user.uid=#{userCustom.uid} and user.username like '%${username}%'
select>
<select id="findUserCount" parameterType="com.liyuan.po.UserQueryVo" resultType="int">
select count(*) from user where user.uid=#{userCustom.uid} anduser.username like '%${username}%'
select>
2)mapper.java
// 用户信息的综合查询
publicList<UserCustom> findUserList(UserQueryVo userQueryVo)
throwsException;
// 用户信息的综合查询总数
publicint findUserCount(UserQueryVo userQueryVo)
throwsException;
6.2.2 resultMap
mybatis中使用resultMap完成高级结果输出映射
如果查询出来的列名和pojo的属性名不一致,通过定义一个resultMap对列名和属性名之间做一个映射
1)mapper.xml
<resultMap type="com.liyuan.po.User" id="userResultMap">
<id column="uid_" property="uid"/>
<result column="username_" property="username"/>
resultMap>
<select id="findUserByIdResultMap" parameterType="int" resultMap="userResultMap">
SELECT uid uid_,username username_ FROM USER WHERE uid=#{id}
select>
2)mapper.java
publicUser findUserByIdResultMap(int uid)throwsException;
7、mybatis的动态sql:
mybatis核心对sql语句进行灵活操作,通过表达式进行判断,对sql进行灵活拼接
7.1 需求 if标签判断
用户信息综合查询列表和用户信息查询总数这两个statement的定义使用动态sql
对查询条件进行判断,如果输入参数不为空,才进行查询条件的拼接
1)mapper.xml
2)接口代码不变
3)测试代码
7.2 需求(sql片段)
将上边实现的动态sql判断代码块抽取出来组成一个sql片段。其他的statement可以来引用这个sql片段
1)定义sql片段
2)在statement中引用sql片段
7.3 foreach
向sql传递数组或list,mybatis用foreach解析
7.3.1 需求
在用户查询列表和列表总数的statement中增加多个uid输入查询
sql语句如下:
两种方法:select * from user where uid=1 or uid=2
select * from user where uid in {1,2}
1)在输入参数包装类型中定义Listnteger>ids 传入多个uid
2)修改mapper.xml
sql片段中
添加