Mybatis

Mybatis概述

Mybatis是什么

Mybatis是一个持久层框架。

Mybatis的作用

Mybatis是一个持久层框架,当然作用就是操作数据库的(增删改查).

为什么需要学习Mybatis

Mybatis的理念:让开发者是10%的代码就可以实现数据库的操作。

解决方案: 持久层(DAO)的零实现。所谓的零实现,就是不用写实现类代码,直接使用接口就可以操作数据库。

Mybatis的定义,提高开发的效率!!!真的写很少代码!!!就可以增删改查。

Mybatis的作用

Mybatis框架能够让我们以最少的代码就可以操作数据库。从而提高开发的效率!!!

如何将代码减少呢?

持久层的零实现 (不需要写实现类):可以自动将数据封装到对象里面不需要手工编写映射的关系 。

Mybatis配置流程图

123

132

  • Resources:资源类,用于读取总配置文件
  • SqlSessionFactoryBuilder:会话工厂构造类,通过读取的总配置文件构建会话工厂
  • SqlSessionFactory:会话工厂
  • SqlSession:会话,就是操作数据库的操作类

入门示例

配置流程说明

  1. 导入包(任何框架需要的事情)
  2. 创建总配置文件,文件名随便写
  3. 创建一个MybatisUtils工具类,(获得操作对象)
  4. 创建一个映射接口
  5. 创建一个映射文件
  6. 在总配置文件加载映射文件。
  7. 编写测试插入数据代码

配置步骤

下载mybatis框架

https://github.com/mybatis/mybatis-3

创建一个普通java项目并导入相关

1234

创建主配置文件 mybatis-config.xml

在项目的 src 下面创建 配置文件 mybatis-config.xml,具体配置参考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">
 
 <!-- mybatis 配置标签,内部就是mybatis的具体配置 -->
<configuration>
  <!-- mybatis的环境配置
        default :默认使用环境,值就是下面环境的id
     -->
  <environments default="mysql">
    <!-- mybatis的具体某一个环境 -->
    <environment id="mysql">
      <!-- MyBatis操作需要事务管理,默认使用 JDBC
            JDBC : MyBatis的别名
       -->
      <transactionManager type="JDBC"/>
      
      <!-- 配置MyBatis的数据源 (连接池)
            POOLED(别名) : MyBatis内置的一个连接池
            后期和Spring集成使用 ,Druid 阿里巴巴连接池
       -->
      <dataSource type="POOLED">
        <!-- 数据库驱动 -->
        <property name="driver" value="com.mysql.jdbc.Driver"/>
        <!-- url地址 -->
        <property name="url" value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8"/>
        <!-- 账号 -->
        <property name="username" value="root"/>
        <!-- 密码 -->
        <property name="password" value="root"/>
      </dataSource>
    </environment>
  </environments>
  
  <!-- 配置映射文件 -->
  <mappers>
        <!-- 读取单个映射文件 -->
        <mapper resource="cn/zj/mybatis/mapper/UserMapper.xml"/>
  </mappers>
</configuration>

创建MyBatisUtil工具类

MyBatisUtil工具类的作用主要用于 读取配置文件,创建工厂对象,提供创建SqlSession数据库操作对象的方法

package cn.zj.mybatis.util;


import java.io.InputStream;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class MyBatisUtil {
    private MyBatisUtil() {
    }
    
    //SqlSessionFactory 会话工厂对象
    private static SqlSessionFactory  factory;
    //类加载到JVM中就立马执行static代码块,并且只会执行一次
    static {
        //资源文件
        String resource = "mybatis-config.xml";
        //try(){}catch(Exception e){} try的圆括号内部能够自动释放/关闭资源
        try(InputStream inputStream = Resources.getResourceAsStream(resource)) {
            //创建SqlSessionFactory 对象
            factory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (Exception e) {
            e.printStackTrace();
        }
        
    }
    /**
     * 创建SqlSession对象
     * @return SqlSession对
     */
    public static SqlSession openSession() {
        //创建Session对象
        SqlSession session = factory.openSession();
        return session;
    }

}

创建数据库表对应的实体类

即 pojo,略

创建一个操作接口

类似于 DAO 接口,命名方式为后缀加 Mapper,例如 UserMapper.java

创建表对应的映射文件 :UserMapper.xml

映射文件的命名与接口名对应,一起放在 mapper 包下。

<?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">

<!--  映射标签,内部就编写具体的映射sql语句
    namespace :命名空间,值 必须是 对应接口的全限定名 = 包名 +简单类名
        cn.zj.mybatis.mapper.UserMapper
 -->
<mapper namespace="cn.zj.mybatis.mapper.UserMapper">
    
    <!-- <insert id="insertUserInfo" parameterType="">
        插入功能标签
            id : 功能唯一标识, 必须接口中对应的方法名一直
            parameterType : 参数类型,必须和接口中方法的参数类型一直
            
            keyColumn="" : 结果集对应的主键列
            keyProperty="" pojo对象对应结果集主键列的属性 
            useGeneratedKeys="true" :是否返回自动生成的主键 true 
            这样设置后,数据库自动生成的主键(如id)会自动添加到用于插入的对象上,便于后续对该对象的操作
     -->
    <insert id="insertUserInfo" parameterType="cn.zj.mybatis.pojo.User"
        keyColumn="id"
        keyProperty="id"
        useGeneratedKeys="true"
    >
        <!-- 
            #{对象属性} : OGNL 表达式语言
         -->
        insert into user (name,password,age)values(#{name},#{password},#{age})
        
    </insert>
    
    <!-- 单行查询
        <select resultType ="">
        查询功能的标签
        
        resultType : 返回结果的数据类型,和接口对应方法的返回类型必须一致
     -->
    <select id="selectByPrimaryKey" parameterType="Integer" resultType="cn.zj.mybatis.pojo.User">
        <!--  #{对象属性} ,主键理论上任何值都可以 #{abc},#{xxx},可以不用对象属性-->
        select * from user where id = #{id}
    </select>
    
    <!-- 多行查询
        无论单行或者多行查询,返回的数据类型都是 对应 pojo 对应的对象类型
     -->
    <select id="selectList" resultType="cn.zj.mybatis.pojo.User">
        select * from user
    </select>
    
    
    <!-- 删除操作 -->
    <delete id="deleteByPrimaryKey" parameterType="Integer">
        delete from user where id = #{id}
    </delete>
    
    
    <!-- 修改操作 -->
    <update id="updateUserInfo" parameterType="cn.zj.mybatis.pojo.User">
        update user set name = #{name},password = #{password},age = #{age} where id = #{id}
    </update>
    
</mapper>

3 log4j日志框架的配置

3.1 说明

log4j是一个日志输出框架,就是用于输出日志的。

Mybatis的日志输出是通过Log4J输出的。主流框架大部分都是Log4j输出的。Spring框架也可以通过Log4j输出日志!!

问题:既然Log4j功能类似System.out.println(),为什么使用log4j而不直接使用System.out.println()?

答:Log4j提供了强大的日志输出的自定义功能。

  1. 通过级别输出日志 (调试、信息、警告、错误、致命异常)
  2. 可以指定输出到控制台,以及输出到文件。
  3. 可以设置输出的日志格式

所以学习LOG4J.需要学会自定义配置LOG4J的输出格式以及输出等级

3.2 下载路径

Log4j的下载地址:http://logging.apache.org/log4j/1.2/

3.3 配置步骤

3.3.1 第一步:导入log4j-1.2.17.jar的包

1233

3.3.2 第二步:在src下创建一个log4j.propertis文件

注意:文件名必须为log4j.properties

# Global logging configuration
log4j.rootLogger=ERROR, stdout
# MyBatis logging configuration...
# log4j.logger.org.mybatis.example.BlogMapper=TRACE
#  前缀(log4j.logger)+点(.)需要记录日志的命名空间 = 日志级别
log4j.logger.cn.zj.mybatis.mapper=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

4 MyBatis完成CRUD操作

5 ResultMap 手动映射

MyBatis的查询结果集都是自动映射封装的,单行查询将数据库一条数据封装成对应的Java对象。多行查询,先将每一行封装成对象,再将每个对象添加到集合中,最后返回一个List集合对象。

但是:必须保证查询结果集和pojo对象的属性名相同,否则无法自动封装

问题: 如何解决查询结果集名称和pojo对象属性不同的映射封装?

解决方案:

  1. 使用手动映射封装 <ResultMap> 标签
  2. 可以使用mybatis的驼峰命名法
<?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">
 <!-- 映射配置
    namespace : 命名空间,通俗讲,每个映射文件唯一的标识名称
  -->
<mapper namespace="cn.zj.mybatis.mapper.UserMapper">

    <!-- 
        resultType : 自动映射
        resultMap : 手动映射,值 自定义对应手动映射标签的 id的值
        注意:自动映射和手动映射二选一,不能同时使用
     -->
    <select id="findByUserId" parameterType="Integer"  resultMap="user_map">
        <!-- #{} OGNL表达式语言  -->
        select id  u_id,name u_name,password u_password ,age u_age from user  where id = #{id}
    </select>
    
    
    <!-- 手动映射
        type :需要手动映射的数据类型
        id :唯一标识
     -->
    <resultMap type="User" id="user_map">
        <!-- 
            主键列映射
            <id column="" property="" javaType="" jdbcType=""/>
            column :结果的列名
            property:domain对象的对应的属性名
            javaType :domian对象的属性的类型(可选,默认自动关联)
            jdbcType :结果集列类型(可选,默认自动关联)
         -->
        <id column="u_id" property="id" javaType="Integer" jdbcType="INTEGER"/>
        
        <!-- 
            主键列映射
            <result column="" property="" javaType="" jdbcType=""/>
            column :结果的列名
            property:domain对象的对应的属性名
            javaType :domian对象的属性的类型(可选,默认自动关联)
            jdbcType :结果集列类型(可选,默认自动关联)
        -->
        <result column="u_name" property="name"/>
        <result column="u_age" property="age"/>
        <result column="u_password" property="password"/>
    </resultMap>
    
    <!-- 多行查询 
        注意:查询不管单行还是多行查询,返回的数据类型都是数据表对应的domain类型
        多行不是返回集合
    -->
    <select id="selectAll" resultMap="user_map">
        select id  u_id,name u_name,password u_password ,age u_age from user
    </select>
</mapper>

6 主配置文件说明与细节配置

总配置文件的标签顺序

  1. properties
  2. settings
  3. typeAliases
  4. typeHandlers
  5. objectFactory
  6. objectWrapperFactory
  7. reflectorFactory
  8. plugins
  9. environments
  10. databaseIdProvider
  11. mappers

6.1 别名typeAliases标签

在UserMapper.xml文件中User无论是作为参数还是作为查询返回数据类型,都需要写上全限定名,实际可以写上简单类名即可,但是需要配置别名

MyBatis框架提供了两种别名机制,一种是自定义别名,一种是内置别名

6.1.1 自定义别名

<!-- 配置类型别名 --> 
<typeAliases>
    
    <!-- 使用包扫描配置别名
        <package name="包名">
        被配置的包下面的所有的类都被取了别名,适用包下面有大量类
        别名就是当前包下面类的简单类名,默认不区分大小
     -->
    <package name="cn.zj.mybatis.pojo"/>
    
    <!-- 配置单个类的别名
        <typeAlias type="" alias=""/> 
        type:要设置别名的数据类型
        alias :别名
     -->
<!-- <typeAlias type="cn.zj.mybatis.pojo.User" alias="User"/> -->
</typeAliases>

如果配置成功,在映射文件里面可以直接使用别名

<select id="findById" parameterType="Integer" resultType="User">
    <!-- #{} OGNL表达式语言  -->
    select * from user where id = #{id}
</select>

6.1.2 内置别名

所谓的内置别名,就是Mybatis框架自带别名。Mybatis已经将常用的数据类型的别名内置声明了,所以这些内置的别名不需要配置就可以直接使用。(不区分大小写)

别名 映射的类型
_byte byte
_long long
_short short
_int int
_integer int
_double double
_float float
_boolean boolean
string java.lang.String
byte Byte
long Long
short Short
int Integer
integer Integer
double Double
float Float
boolean Boolean
date java.util.Date
decimal BigDecimal
bigdecimal BigDecimal
object Object
map java.util.Map
hashmap HashMap
list List
arraylist ArrayList
collection Collection
iterator Iterator

6.2 properties 读取配置文件

一般开发会将单独的数据库连接字符串配置到一个独立的 以 .properties 的配置文件中

Mybaits框架中配置文件 的 <properties> 标签可以读取配置文件中的内容。并可以使用 ${} 的语法设置给框架的数据库连接操作代码

6.2.1 在classpath下面创建一个db.properties数据库连接配置文件

jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8
jdbc.username=root
jdbc.password=root

6.2.2 在mybatis-config.xml主配置文件中配置<properties>标签读取配置文件

<properties resource="db.properties"/>

6.2.3 连接数据库的配置修改为 ${key}的方式

<dataSource type="POOLED">
    <property name="driver" value="${jdbc.driverClassName}"/>
    <property name="url" value="${jdbc.url}"/>
    <property name="username" value="${jdbc.username}"/>
    <property name="password" value="${jdbc.password}"/>
</dataSource>

6.3 settings标签

Mybatis默认设置了很多默认配置.有时候,我们需求与默认的配置的参数不一样,我们就需要修改这些默认配置的参数.

如:Mybatis已经对骆驼命名法的支持,但默认是不开启的.可以通过 mapUnderscoreToCamelCase 参数设置为 true 支持

7 MyBatis的注解开发

MyBatis的映射配置除了使用xml配置以外,还支持注解配置sql语句

问题: 为什么有了xml配置还有注解配置

答 :MyBatis的注解开发更简洁,只需要将对应的SQL语句的注解标注对应的功能方法上即可,直接连 XxxMapper.xml映射文件都可以省略了

本身注解开发就是Java配置的一种趋势,后期学习SpringBoot时候,发现全部用纯注解配置

MyBatis提供了下面注解进行映射文件配置

@Select 查询数据注解
@Insert 插入数据注解
@Delete 删除数据注解
@Update 修改数据注解
@Options 选项配置
@Results 手动映射配置
@Result @results中的具体的某一列的映射信息配置

7.1 案例代码

package cn.zj.mybatis.mapper;
import java.util.List;

import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.One;
import org.apache.ibatis.annotations.Options;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.ResultMap;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;

import cn.zj.mybatis.domain.User;


public interface UserMapper {
    
    /**
     * 插入用户数据
     * @param user 封装有用户信息的User对象
     * @return  受影响的行数
     */
    @Insert("insert into user (name,password,age)values(#{name},#{password},#{age})")
    /*
     * @Options
     *  注解可选项配置
     *  keyColumn :结果集对应的主键列
     *  keyProperty pojo对象对应主键列属性
     *  useGeneratedKeys 是否返回自动生成的主键 true是
     */
    @Options(keyColumn="id",keyProperty="id",useGeneratedKeys=true)
    int insertUserInfo(User user);
    
    
    /**
     * 单行查询
     * @param id 主键id
     * @return  查询结果封装的User对象
     */
    @Select("select id u_id,name u_name,password u_password,age u_age from user where id = #{id}")
    /*
     * 结果集封装映射 
     * @Results
     *  @Rsutlt 具体某一列属性的映射
     *      id :是否是主键列
     *      column :结果集的列明
     *      property :pojo对象对应的属性名
     */
    @Results({
        @Result(id=true,column="u_id",property="id"),
        @Result(column="u_name",property="name"),
        @Result(column="u_password",property="password"),
        @Result(column="u_age",property="age")
    })
    User selectByPrimaryKey(int id);
    
    
    /**
     * 多行查询
     * @return 结果集封装的对象
     */
    @Select("select * from user")
    List<User> selectList();
    
    /**
     * 删除操作
     * @param id 主键id
     * @return 受影响的行数
     */
    @Delete("delete from user where id = #{id}")
    int deleteByPrimaryKey(int id);
    
    /**
     * 修改操作
     * @param user 带有id的user对象
     * @return 受影响的行数
     */
    @Update("update user set name = #{name},password = #{password},age = #{age} where id = #{id}")
    int updateUserInfo(User user);
}

7.2 注解映射的配置

<mappers>
    <!-- 配置具体的映射文件 ,映射xml文件-->
<!--  <mapper resource="cn/zj/mybatis/mapper/UserMapper.xml"/>  -->
    <!-- 接口映射权限定名 -->
    <mapper class="cn.zj.mybatis.mapper.UserMapper"/>
</mappers>

8 方法多参数传递使用-@Param注解

Mybatis默认情况下是不支持传入多个参数的.只能传入一个参数.

所谓的传入参数指定是Mybatis操作(<insert><delete><update><select>)的传入参数.

方案1:将这些参数封装到一个对象里面(JavaBean/Map),再传入.
方案2:给参数设置一个@Param注解支持,而且多参数的类型要统一

问题:为什么不支持多个参数?

因为Java语法1.7以前.是不能通过反射技术获得方法的参数名的.

解决方案:使用 @Param 参数注解


import java.util.Map;

import org.apache.ibatis.annotations.Param;

import cn.zj.mybatis.domain.User;

public interface UserMapper {
    
    /**
     * 模拟登陆操作
     * @param user 封装有账号密码的User对象
     * @return 查询结果封装的User对象
     */
    User login1(@Param("name")String name,@Param("pwd")String password);
}

xml 配置如下:

<select id="login1" parameterType="string" resultType="cn.zj.mybatis.pojo.User">
    select * from user where name = #{name} and password = #{pwd}
</select>   

9 #{}与${}的区别

在MyBatis框架中支持两种 OGNL语法

#{} 基于 JDBC 的 PreparedStatement 类,SQL 语句参数使用 ? 占位符,在运行阶段动态设置参数,但是 ? 不能作为表名。

预编译语句对象的SQL语句只能 操作 DML和DQL 语句,不能操作DDL语句

  1. #{}表示设置预编译的参数,就是 ? 的参数,所以如果要不固定的表名不能使用 #{},只能使用 ${}
  2. ${} 直接把值输出来,直接把参数拼接到 SQL 语句中.而 #{] 是使用 ? 来代替. 所以 ${} 是不安全的.
  3. ${} 只能获得参数池的值,而 #{} 可以获得方法的参数值,也可以获得参数池的值,如果使用 ${} 获得参数的值,这个参数必须要加上 @Param

如果非必要情况,不要使用${}

问题:那么${}有什么用呢?

答:注意基于JDBC的接口的原来的表名是不可以使用?的,?只能用于传入的参数。如果操作的涉及表名这些非参数的 数据时,需要使用${}

posted @ 2019-07-01 22:17  Carlos_Ouyang  阅读(...)  评论(...编辑  收藏