Java之Mybatis
Mybatis
Mybatis简介
什么是Mybatis?
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
Mybatis作用
数据持久化:
持久化就是将程序的数据在持久状态和瞬时状态转换的过程
持久层主要是写完成持久化操作的代码块
而Mybatis就一个优秀的持久层框架
帮助程序员将数据存入数据库中,传统JDBC代码太复杂了,Mybatis可以更方便操作持久化层,容易上手
技术没有高低之分,只有掌握技术的人有高低之分
优点:
- 简单易学
- 灵活
- sql与代码分离,降藕
- 提供映射标签,支持对象与数据库的orm字段关系映射
- 提供对象关系映射标签,支持对象关系组建维护
- 提供xml标签,支持动态编写sql
Mybatis-config.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>
<!-- mybatis环境-->
<environments default="development">
<!-- 第一个环境,id处也可以是default-->
<environment id="development">
<!-- JDBC事务-->
<transactionManager type="JDBC"/>
<!-- 连接数据库配置-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT-8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/zh1z3ven/mapper/UserMapper.xml"/>
</mappers>
</configuration>
注册Mapper的小tips
可以借助*实现匹配所有Mapper.xml
<mappers>
<mapper resource="com/zh1z3ven/mapper/*Mapper.xml"/>
</mappers>
Mybatis.Utils
因为上面说到了SqlSession实例对象才可以进行对于数据库的操作,这里封装了这个获取sqlSession的步骤
主要是通过:SqlSessionFactoryBuilder > SqlSessionFactory> SqlSession实例==>执行sql语句,操作数据库
//SqlSessionFactoryBuilder ==> SqlSessionFactory
//SqlSessionFactory ==> SqlSession实例
//sqlSession可以执行sql语句,操作数据库
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory;
//从xml配置生成SqlSessionFactory实例
static{
try {
String resource = "mybatis-config.xml";
InputStream inputStream = null;
inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
//获取sqlSession,操作数据库
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
}
}
Mapper接口与Mapper.xml配置文件
这里利用Mapper接口和Mapper.xml配置文件替代了原先的Dao+实现类的操作。
UserMapper接口
public interface UserMapper {
public List<User> getUserList();
}
UserMapper.xml
可以将Mapper.xml看作是Mapper接口的实现类
namespace
绑定dao
层接口:namespace="com.zh1z3ven.mapper.UserMapper"
id
指定此标签中的sql语句对应于dao层接口的哪个方法:id="getUserList"
resultType
设置返回值类型,此处返回的User
类型的对象resultType="com.zh1z3ven.pojo.User"
<?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.zh1z3ven.mapper.UserMapper">
<select id="getUserList" resultType="com.zh1z3ven.pojo.User">
select * from user
</select>
</mapper>
SqlSession对象
获取sqlSession对象
String resource = "mybatis-config.xml";
InputStream resourceAsStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
封装成工具类
MybatisUtils
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory;
static {
try {
String resource = "mybatis-config.xml";
InputStream inputStream = null;
inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
}
}
Mybatis-Select
方法一、getMapper()
sqlSession.getMapper(UserMapper.class);
public class test {
@Test
public void testSql(){
//获取sqlSession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
//sqlSession.getMapper()执行SQL
//调用实现类的getUserList方法
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = userMapper.getUserList();
//遍历输出
for (User user : userList) {
System.out.println(user);
}
//关闭资源
sqlSession.close();
}
}
方法二、sqlSession.selectList()
sqlSession.selectList("com.zh1z3ven.mapper.UserMapper.getUserList");
public class test {
@Test
public void testSql(){
//获取sqlSession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
//sqlSession.select("com.zh1z3ven.UserMapper.getUserList") 执行sql
List<User> userList = sqlSession.selectList("com.zh1z3ven.mapper.UserMapper.getUserList");
//遍历输出
for (User user : userList) {
System.out.println(user);
}
//关闭资源
sqlSession.close();
}
}
Mybatis-CRUD
增删改操作需要提交事务才可以完成
Mybatis-Add
UserMapper
int addUser(User user);
UserMapper.xml
<!-- 对象中的属性可以直接取出来-->
<insert id="addUser" parameterType="com.zh1z3ven.pojo.User">
insert mybatis.user(id, name , pwd) values(#{id}, #{name}, #{pwd})
</insert>
testAddUser
@Test
public void testAddUser(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
int i = mapper.addUser(new User(4, "ago", "123321"));
if (i>0){
System.out.println("Add User Success");
}
//提交事务
sqlSession.commit();
sqlSession.close();
}
Mybatis-Update
UserMapper
int updateUser(User user);
UserMapper.xml
<update id="updateUser" parameterType="com.zh1z3ven.pojo.User">
update mybatis.user set pwd = #{pwd} where id = #{id} and name = #{name}
</update>
testUpdateUser()
//修改user
@Test
public void testUpdateUser(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
int i = mapper.updateUser(new User(4, "ago", "123123"));
if (i>0){
System.out.println("Update User Success");
}
sqlSession.commit();
sqlSession.close();
}
Mybatis-Delete
UserMapper
int delUser(User user);
UserMapper.xml
<delete id="delUser" parameterType="com.zh1z3ven.pojo.User">
delete from mybatis.user where id = #{id} and name = #{name} and pwd = #{pwd}
</delete>
testDeleteUser()
@Test
public void testDeleteUser(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
int i = mapper.delUser(new User(4, "ago", "123123"));
if (i>0){
System.out.println("Delete User Success");
}
sqlSession.commit();
sqlSession.close();
}
Mybatis-Map
普通传参
当数据库需要操作的表的字段或者xml中sql语句需要传入的参数过多时可以考虑用Map传递参数
UserMapper
int addUser2(Map<String,Object> map);
UserMapper.xml
<insert id="addUser2" parameterType="map">
insert mybatis.user(id, name, pwd) values(#{userId}, #{userName}, #{userPassword})
</insert>
test
@Test
public void addUser2(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
Map<String, Object> map = new HashMap<String, Object>();
map.put("userId", 6);
map.put("userName", "zh1z3ven");
map.put("userPassword", "12344321");
int i = mapper.addUser2(map);
if (i>0){
System.out.println("Add User With Map Success");
}
sqlSession.commit();
sqlSession.close();
}
模糊查询
模糊查询时需要使用到通配符%,一般放在java代码里
UserMapper
List<User> getUserLike(String value);
UserMapper.xml
<select id="getUserLike" resultType="com.zh1z3ven.pojo.User">
select * from user where name like #{value}
</select>
test
@Test
public void testGetUserLike(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("value", "li");
List<User> userList = mapper.getUserLike("%li%");
for (User user : userList) {
System.out.println(user);
}
sqlSession.close();
}
Mybatis-配置解析
Mybatis-config.xml核心配置文件
环境配置(environments)
mybatis可以适应多种环境,但是SqlSession只能一次用于一种环境
一般通过id属性来配置sql环境
通过default属性选择要使用的sql环境
<environments default="development">
transactionManager(事务管理器)有两种事务管理器JDBC和MANAGED,一般用JDBC可以提交事务和事务回滚。
<transactionManager type="JDBC"/>
dataSource(数据源)用于连接数据库,默认为POOLED,有池的连接
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT-8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
属性(properties)
通过配置属性来引用配置文件
之前是像下面一样直接把连接数据库所需的driver url 等写死的,也可以不写死
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT-8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
通过properties引入外部配置文件
<properties resource="db.properties">
</properties>
<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>
- 可以直接引入外部文件
- 可以在其中增加一些属性配置
- 如果两个文件同时有同名字段,优先使用外部配置文件的
类型别名(typeAliases)
设置返回类型的别名。只和xml有关,用来减少完全限定名的冗余。
通过指定一个类来给起短名
<typeAliases>
<typeAlias type="com.zh1z3ven.pojo.User" alias="User"/>
</typeAliases>
通过扫描package来指定JavaBean
在没有注解的情况下会使用JavaBean的小写名来当作别名
<typeAliases>
<package name="com.zh1z3ven.pojo"/>
</typeAliases>
使用注解形式起别名(在使用扫描package的情况下)
@Alias("类名")
settings(设置)
logImpl => 指定日志实现
映射器(mappers)
方式一:通过指定资源文件xml注册
<mappers>
<mapper resource="com/zh1z3ven/mapper/UserMapper.xml"/>
</mappers>
方式二:通过class指定映射
<mappers>
<mapper class="com.zh1z3ven.mapper.UserMapper"/>
</mappers>
- 接口和他的Mapper配置文件必须同名
- 接口和他的Mapper配置文件必须在同一个包下
方式三:使用package
<mappers>
<package name="com.zh1z3ven.mapper.UserMapper"/>
</mappers>
ResultMap
解决属性名和字段名不一致的问题
将数据表中的列与实体类中的属性对应上
UserMapper.xml
<resultMap id="" type="UserMap">
<result column="id" property="id"/> <!--column对应数据表中字段,property对应javabean中属性-->
<result column="name" property="username"/>
<result column="pwd" property="password"/>
</resultMap>
<!--指定resultMap名字为UserMap-->
<select id="getUserList" resultMap="UserMap">
select * from user
</select>
设置日志
标准日志输出
在mybatis核心配置文件中添加如下:
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
Log4j
Log4j是Apache的开源项目,Log4j可以控制日志输出的地方为控制台、GUI组件、文件等;可以设置输出日志的等级;只需要操作配置文件即可,无需改动代码。
Log4j.properties
#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
log4j.rootLogger=DEBUG,console,file
#控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n
#文件输出的相关设置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/kuang.log
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n
#日志输出级别
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
在mybatis核心文件中配置log4j
mybatis-config.xml
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
简单使用
//设置log为当前类
static Logger logger = Logger.getLogger(test.class);
@Test
public void testLog4j(){
//设置log级别
logger.info("info:进入了Log4j");
logger.debug("debug:进入了Log4j");
logger.error("error:进入了Log4j");
}
public void testSql(){
//获取sqlSession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
logger.info("info:获取SqlSession对象成功");
List<User> userList = sqlSession.selectList("com.zh1z3ven.mapper.UserMapper.getUserList");
//遍历输出
for (User user : userList) {
logger.info("info:用户:" + user);
}
//关闭资源
sqlSession.close();
logger.info("info:关闭资源");
}
Mybatis-注解实现CRUD
之前提到的都是用Mapper映射xml实现的sql语句操作数据库,sql语句主要是写到了xml文件中,Mybatis还提供了注解实现sql语句操作数据库,更加简化了代码编写。但是如果是更复杂的sql,还是需要用xml来编写,注解的方式只适合一些简单的sql语句。
mybatis-config.xml 绑定接口(注意用注解绑定的就是接口,)
<mappers>
<mapper class="com.zh1z3ven.mapper.UserMapper"></mapper>
</mappers>
UserMapper
public interface UserMapper {
//查询所有用户
@Select("select * from user")
List<User> getUserList();
}
test
static Logger logger = Logger.getLogger(test.class);
@Test
public void testGetUserList(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = mapper.getUserList();
for (User user : userList) {
logger.info("info:"+user);
}
sqlSession.close();
}
在mybatis-config.xml注册Mapper(这里不能像xml可以用*匹配所有,需要一个一个注册)
<mappers>
<mapper class="com.zh1z3ven.mapper.UserMapper"></mapper>
</mappers>
接口
//查询所有用户
@Select("select * from user")
List<User> getUserList();
//根据id查询用户,利用@param注解传参
@Select("select * from user where id = #{id}")
User getUserById(@Param("id") int id);
//add user
@Insert("insert into user (id, name, pwd) values (#{id}, #{username}, #{password})")
int addUser(Map map);
//update user
@Update("update user set name=#{username},pwd=#{password} where id = #{id}")
int updateUser(User user);
//delete user
@Delete("delete from user where id = #{id}")
int deleteUser(@Param("id") int id);
关于@Param注解
- 用于基本类型或String,引用类型不需要
- 在sql中引用的就是这里@Param中的值
关于#{}与${}
{}为预编译;${}为直接拼接,可能引发sql注入
Mybatis-动态SQL
动态SQL:利用Mybatis中自带的标签,根据不同的条件生成不同的SQL语句。
简单来说,我们之前利用JDBC写dao层的时候,是没有办法处理sql语句逻辑的,处理逻辑只能在上层实现,那么就造成了可能需要写很多的sql,而动态sql可以帮助我们在mybatis中实现部分的逻辑处理,简化一部分的开发。
在Mybatis中有4种标签
if
choose(when, otherwise)
trim(where, set)
foreach
if
类似于java中if else语句
<select id="StudentMapper" parameterType="Map" resultMap="Student">
select * from user where
<if test="id != null!">
id = #{id}
</if>
</select>
trim(where, set)
trim标签可以定制where元素的一些功能, trim标签有几个属性值。
prefix=""
prefixOverrides=""
suffix=""
suffixOverrides=""
移除指定在prefixOverrides的内容并且插入prefix中指定的内容
当然如果类似于上面if标签那样拼接语句时如果有多个条件的情况下,还是形容上面那样写可能就会报错,例如
<select id="StudentMapper" parameterType="Map" resultMap="Student">
select * from user where
<if test="id != null!">
id = #{id}
</if>
<if test="id != null!">
and name = #{name}
</if>
</select>
如果此时之匹配到了name条件的话,sql就会变成
select * from user where and name = xxx;
这样是会出现bug的,正常逻辑应该是如果只匹配到了name参数但是他的sql语句中有and关键字,那么需要去除掉这个and。
而where标签就很好的解决了这个事情:将原sql中的where去掉,改用where标签代替即可
<select id="StudentMapper" parameterType="Map" resultMap="Student">
select * from user
<where>
<if test="id != null!">
id = #{id}
</if>
<if test="name != null!">
and name = #{name}
</if>
</where>
</select>
set 元素可以用于动态包含需要更新的列,忽略其它不更新的列;
set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)
可以配合if或者choose来筛选需要更新的列
<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>
choose(when, otherwise)
类似于java中swtich case语句,满足when标签中的表达式,则执行该when中的sql语句,若都不满足则执行otherwise中的sql语句
<select id="StudentMapper" parameterType="Map" resultMap="Student">
select * from user
<where>
<choose>
<when test="id != null!">
id = #{id}
</when>
<when test="name != null!">
and name = #{name}
</when>
<otherwise>
and 1=1
</otherwise>
</choose>
</where>
</select>