mybatis01-简介

0.拓展

1.jdbc操作数据库

1.1 maven依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>mybatis-study</artifactId>
        <groupId>com.myx</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <packaging>jar</packaging>
    <artifactId>jdbc-demo</artifactId>
    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.2</version>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>4.1.19</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.6.1</version>
        </dependency><dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.30</version>
    </dependency>
    </dependencies>
</project>

1.2 java代码

import java.sql.*;

/**
 * 描述:jdbc test
 * @author: myx
 * @date: 2019/1/7
 * 注意:本内容仅限于学习使用
 * Copyright © 2019-myx. All rights reserved.
 */
public class JdbcTest {
    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        try {
            //加载数据库驱动
            Class.forName("com.mysql.jdbc.Driver");
            //通过驱动管理类获取数据库链接
            connection = DriverManager.getConnection("jdbc:mysql://140.143.193.83:3306/mybatis-test?characterEncoding=utf-8","iot", "123456");
            //定义sql语句 ?表示占位符
            String sql = "select * from user where username = ?";
            //获取预处理statement
            preparedStatement = connection.prepareStatement(sql);
            //设置参数,第一个参数为sql语句中参数的序号(从1开始),第二个参数为设置的参数值
            preparedStatement.setString(1, "myx");
            //向数据库发出sql执行查询,查询出结果集
            resultSet = preparedStatement.executeQuery();
            //遍历查询结果集
            while(resultSet.next()){
                System.out.println(resultSet.getString("id")+" "+resultSet.getString("username"));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            //释放资源
            if(resultSet!=null){
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(preparedStatement!=null){
                try {
                    preparedStatement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(connection!=null){
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

1.3 传统 JDBC 的弊端

  • jdbc 底层没有用连接池、操作数据库需要频繁的创建和关联链接。消耗很大的资源
  • 写原生的 jdbc 代码在java中,一旦我们要修改sql的话,java需要整体编译,不利于系 统维护
  • 使用 PreparedStatement预编译的话对变量进行设置123数字,这样的序号不利于维护
  • 返回 result 结果集也需要硬编码。

2.现阶段数据访问层框架

在这里插入图片描述

2.什么是mybatis

MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。

2.1 参考手册

官网手册

2.2 mybatis架构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IZMA557Y-1575011562629)(WEBRESOURCE178f5c19efd4b84cb23d7bed9d918a38)]

try {
    // 1.mybatis配置文件
    String resources = "mybatis.xml";
    // 2.获取Reader对象
    Reader resourceAsReader = Resources.getResourceAsReader(resources);
    // 3.获取SqlSessionFactoryBuilder
    SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsReader);
    // 4.创建对应的session
    SqlSession sqlSession = build.openSession();
    // 5.获取对应的mapper
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    // 6.执行方法
    UserEntity user = userMapper.getUser(1);
    System.out.println("name:" + user.getName());
} catch (Exception e) {
    e.printStackTrace();
}

3.helloword(xml)

官网教程

4.mybatis全局注解详解

官网参考

5.mybatis注解实现

5.1 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>
    <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://140.143.193.83:3306/mybatis-test"/>
                <property name="username" value="iot"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <!--xml方式-->
        <!--<mapper resource="mapper/UserMapper.xml"/>-->
        <!--注解方式-->
        <package name="com.myx.mybatis"></package>
    </mappers>
</configuration>

5.2 UserMapper

import org.apache.ibatis.annotations.Select;

/**
 * 描述:userMapper接口
 * @author: myx
 * @date: 2019/1/7
 * 注意:本内容仅限于学习使用
 * Copyright © 2019-myx. All rights reserved.
 */
public interface UserMapper {
    @Select("select * from user where id =#{id}")
    public User selectUser(int id);
}

6.Mybatis 之注解和 xml 优缺点

  • Xml:增加 xml 文件、麻烦、条件不确定、容易出错,特殊字符转义
  • 注释:不适合复杂 sql,收集 sql 不方便,重新编译

7.Mybatis 之#与$区别

7.1 #{}表示一个占位符号

通过#{}可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换,#{}可以有效防止sql注入。#{}可以接收简单类型值或pojo属性值。 如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称。

7.2 ${}表示拼接sql串

通过${}可以将parameterType传入的内容拼接在sql中且不进行jdbc类型转换, 可 以 接 收 简 单 类 型 值 或 p o j o 属 性 值 , 如 果 p a r a m e t e r T y p e 传 输 单 个 简 单 类 型 值 , {}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值, pojoparameterType{}括号中只能是value。

7.3 OGNL

Object Graphic Navigation Language
对象 图 导航 语言

它是通过对象的取值方法来获取数据。在写法上把get给省略了。
比如:我们获取用户的名称:

  • 类中的写法:user.getUsername();
  • OGNL表达式写法:user.username

mybatis中为什么能直接写username,而不用user.呢:因为在parameterType中已经提供了属性所属的类,所以此时不需要写对象名。
Mybatis使用ognl表达式解析对象字段的值,#{}或者${}括号中的值为pojo属性名称。

8.Mybatis 之 parameterType 与 parameterMap 区别

  • parameterMap和resultMap类似,parameterMap通常应用于mapper中有多个参数要传进来时,表示将查询结果集中列值的类型一一映射到java对象属性的类型上,在开发过程中不推荐这种方式。
  • parameterType直接将查询结果列值类型自动对应到java对象属性类型上,不再配置映射关系一一对应。

9.Mybatis 之 resultType 与 resultMap 区别

  • 使用 resultType进行输出映射,只有查询出来的列名和pojo中的属性名一致,该列才可以映射成功。
  • mybatis 中使用 resultMap 完成高级输出结果映射(自定义映射)。

10.mybatis插件

10.1 官网简介

插件

10.2 实现显示sql插件

import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.ParameterMode;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.type.TypeHandlerRegistry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import java.util.regex.Matcher;

@Intercepts
        ({
                @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
                @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})
        })
public class SqlPrintInterceptor implements Interceptor{

    private static final Logger log = LoggerFactory.getLogger(SqlPrintInterceptor.class);

    private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
        Object parameterObject = null;
        if (invocation.getArgs().length > 1) {
            parameterObject = invocation.getArgs()[1];
        }

        long start = System.currentTimeMillis();

        Object result = invocation.proceed();

        String statementId = mappedStatement.getId();
        BoundSql boundSql = mappedStatement.getBoundSql(parameterObject);
        Configuration configuration = mappedStatement.getConfiguration();
        String sql = getSql(boundSql, parameterObject, configuration);

        long end = System.currentTimeMillis();
        long timing = end - start;
        if(log.isInfoEnabled()){
            log.info("执行sql耗时:" + timing + " ms" + " - id:" + statementId + " - Sql:" );
            log.info("   "+sql);
        }

        return result;
    }

    @Override
    public Object plugin(Object target) {
        if (target instanceof Executor) {
            return Plugin.wrap(target, this);
        }
        return target;
    }

    @Override
    public void setProperties(Properties properties) {
    }

    private String getSql(BoundSql boundSql, Object parameterObject, Configuration configuration) {
        String sql = boundSql.getSql().replaceAll("[\\s]+", " ");
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
        TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
        if (parameterMappings != null) {
            for (int i = 0; i < parameterMappings.size(); i++) {
                ParameterMapping parameterMapping = parameterMappings.get(i);
                if (parameterMapping.getMode() != ParameterMode.OUT) {
                    Object value;
                    String propertyName = parameterMapping.getProperty();
                    if (boundSql.hasAdditionalParameter(propertyName)) {
                        value = boundSql.getAdditionalParameter(propertyName);
                    } else if (parameterObject == null) {
                        value = null;
                    } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
                        value = parameterObject;
                    } else {
                        MetaObject metaObject = configuration.newMetaObject(parameterObject);
                        value = metaObject.getValue(propertyName);
                    }
                    sql = replacePlaceholder(sql, value);
                }
            }
        }
        return sql;
    }

    private String replacePlaceholder(String sql, Object propertyValue) {
        String result;
        if (propertyValue != null) {
            if (propertyValue instanceof String) {
                result = "'" + propertyValue + "'";
            } else if (propertyValue instanceof Date) {
                result = "'" + DATE_FORMAT.format(propertyValue) + "'";
            } else {
                result = propertyValue.toString();
            }
        } else {
            result = "null";
        }
        return sql.replaceFirst("\\?", Matcher.quoteReplacement(result));
    }
}

11.MyBatis的动态SQL

MyBatis的强大特性之一便是它的动态SQL,以前拼接的时候需要注意的空格、列表最后的逗号等,现在都可以不用手动处理了,MyBatis采用功能强大的基于OGNL的表达式来实现,下面主要介绍下。

11.1 if标签

if是最常用的判断语句,主要用于实现某些简单的条件选择。基本使用示例如下:

<select id="queryAllUsersByName" resultType="com.example.springboot.mybatisxml.entity.User">
    select * from user where 1=1
    <if test="name != null and name != ''">
        and name = #{name}
    </if>
    <if test="age != null ">
        and age = #{age}
    </if>
</select>

11.2 where标签

上面的例子中使用了“1=1”,是为了避免后续条件不满足时候报错,那有没有办法避免这种写法呢?
当然有,就是接下来要说的,标签会自动判断如果包含的标签中有返回值的话,就在sql中插入一个‘where’,如果where标签最后返回的内容是以and 或者or开头的,也会被自动移除掉,上面例子中换成“where”标签后写法如下:

<select id="queryAllUsersByName" resultType="com.example.springboot.mybatisxml.entity.User">
    select * from user 
    <where>
        <if test="name != null and name != ''">
            and name = #{name}
        </if>
        <if test="age != null ">
            and age = #{age}
        </if>
    </where>
</select>

11.3 trim标签

trim的作用是去除特殊的字符串,它的prefix属性代表语句的前缀,prefixOverrides属性代表需要去除的哪些特殊字符串,prefixOverrides属性会忽略通过管道分隔的文本序列(注意此例中的空格也是必要的),后缀的处理和前缀一样。

trim标签的主要属性如下

  • prefix:前缀覆盖并增加其内容。
  • suffix:后缀覆盖并增加其内容。
  • prefixOverrides:前缀判断的条件。
  • suffixOverrides:后缀判断的条件。

举两个例子。

  • 使用前缀属性
<select id="queryAllUsersByName" resultType="com.example.springboot.mybatisxml.entity.User">
    select * from user
    <trim prefix="WHERE" prefixOverrides="AND |OR " >
        <if test="name != null and name != ''">
            and name = #{name}
        </if>
        <if test="sex != null ">
            or sex = #{sex}
        </if>
        <if test="age != null ">
            and age = #{age}
        </if>
    </trim>
</select>
  • 使用后缀属性
<update id="update" parameterType="Object">
    UPDATE user
    <trim suffix=" SET " suffixOverrides=",">
        <if test="id != null ">id=#{id},</if>
        <if test="name != null ">name=#{name},</if>
        <if test="age != null ">age=#{age},</if>
    </trim>
    WHERE ID=#{id}
</update>

11.4 foreach标签

作用是遍历集合,它能够很好地支持数组和List、Set接口的集合的遍历,往往和sql中的in组合比较多。

foreach标签的主要属性如下

  • item:表示循环中当前的元素。
  • index:表示当前元素在集合的位置下标。
  • collection:配置list的属性名等。
  • open和close:配置的是以什么符号将这些集合元素包装起来。
  • separator:配置的是各个元素的间隔符。
<select id="queryAllUsersByName" resultType="com.example.springboot.mybatisxml.entity.User">
    select * from user where id in
    <foreach item="id" index="index" collection="userList"
             open="(" separator="," close=")">
        #{id}
    </foreach>
</select>
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值