Loading

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&amp;useUnicode=true&amp;characterEncoding=utf-8&amp;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接口的实现类

  1. namespace绑定dao层接口:namespace="com.zh1z3ven.mapper.UserMapper"
  2. id指定此标签中的sql语句对应于dao层接口的哪个方法:id="getUserList"
  3. 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&amp;useUnicode=true&amp;characterEncoding=utf-8&amp;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&amp;useUnicode=true&amp;characterEncoding=utf-8&amp;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>
posted @ 2021-08-26 01:11  Zh1z3ven  阅读(166)  评论(0编辑  收藏  举报