MyBati潜入深出(一)

一、MyBatis介绍

问:什么是框架?

框架是软件开发中的一套解决方案,MyBatis就是用来解决持久层的问题的框架。框架封装了好多重复且细节的步骤,使开发者大大提高项目开发效率。

持久层技术解决方案:底层基本都基于JDBC技术。

1、Sping的JbdcTemplate:spring对jdbc的简单封装。
2、Apache的DButils:该工具也是对jdbc的简单封装。
以上都不算是框架, JbdcTemplate和DButils只是工具类,依然存在很多重复冗余的东西。

1.1、MyBatis框架概述

  MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架,其主要就完成2件事情:

1、更加完善的封装JDBC操作
2、利用反射打通Java类与SQL语句之间的相互转换
3、采用ORM思想解决实体与数据映射的问题

其中,Mybatis整体构造由 数据源配置文件、Sql映射文件、会话工厂、会话、执行器和底层封装对象组成。

面试题:JDBC、hibenate框架和MyBatis框架的关系和区别是什么?
hibenate和MyBatis框架的底层都是基于JDBC来实现的。
(1)JDBC是一种与数据库交互的技术,其中JDBC就像是一个人用手洗衣服,从衣服搓洗,到衣服漂洗和甩干都是人为在做。JDBC也是从SQL的编写、预编译、设置参数、拿到返回结果,关闭数据库连接等一系列操作都,比较笨重,步骤繁杂。
(2)hibenate框架相当于一个全自动化洗衣机,只需要将衣服丢进入洗机器,一些列操作都自动完成。也就是hibenate框架只需要配置了实体与数据表的映射关系,其他的编写SQL等一些列步骤,直接调其中封账方法即可。优点就是比较便捷,高效,缺点就是不够灵活。如果一台洗衣机想要将洗衣机中的衣物分开脱水,或不同程度的烘干,那么全自动洗衣机都比较难做到。同样的,hibenate确实高效方便,但是想要做到结果集只返回个别字段或其他高难度的SQL,需要去学习HQL查询语言,对于开发者来说增加了项目的开发难度。
(3)MyBatis框架相当于一个半自动洗衣机,除了配置数据表与实体的映射关系外,还将自己编写SQL的环境从全自动洗衣机提取出来,使用配置文件去维护。优点:注重SQL的编写,框架灵活,简单易维护。

二、MyBatis环境搭建

步骤:
1、新建maven工程并导入依赖(mybatis、mysql)
2、创建实体类和Dao接口
3、创建MyBatis的配置文件
4、创建映射配置文件

2.1、新建一个Maven工程
在这里插入图片描述
并在pom文件中导入相关依赖:
下载jar链接:https://repo.maven.apache.org/maven2/

在这里插入图片描述

2.2、创建实体类和Dao接口
(1)创建一张用户表并加入数据:
在这里插入图片描述

(2)创建User 实体类,字段与数据库字段一一对应:

Java的"对象序列化"能让你将一个实现了Serializable接口的对象转换成一组byte,这样日后要用这个对象时候,你就能把这些byte数据恢复出来,并据此重新构建那个对象了。这一点甚至在跨网络的环境下也是如此,这就意味着序列化机制能自动补偿操作系统方面的差异。

在这里插入图片描述
(3)新建一个Dao接口:
在这里插入图片描述
2.3、创建MyBatis配置文件(MyBatis全局配置文件)
(1)创建MyBatis配置文件,对文件名称没有规定。

引入全局配置文件dtd约束(帮助检查配置是否合法)

在这里插入图片描述
代码如下:

<?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="mysql">
        <!--配置MySQL的环境 -->
        <environment id="mysql">
            <!--配置事务类型 -->
            <transactionManager type="JDBC"></transactionManager>
            <!--配置数据源(连接池) -->
            <dataSource type="POOLED">
                <!--配置链接数据库的4个基本信息 -->
                <property name="driver" value="com.mysql.jdbc.Driver" />
                <property name="url" value="jdbc:mysql://localhost:3306/test" />
                <property name="username" value="root" />
                <property name="password" value="123456" />
            </dataSource>
        </environment>
    </environments>

    <!--指定映射文件的位置,映射配置文件指的是每个dao独立的配置文件 -->
    <mappers>
        <mapper resource="mapper/IUserDao.xml" />
    </mappers>
</configuration>

注意:(1)<mapper>标签中,resource,class,url在同一个mapper标签只能出现一种。
加载Mapper的四种方式可读文章:
https://blog.csdn.net/bestcxx/article/details/72966768
(2)其实MyBatis全局配置文件和Mapper配置文件可以没有,需要通过注解或编码的方式实现与数据库交互。在MyBatis官方文档中有写实现数据库交互的方法,这里不详说。

2.4、 配置映射配置文件
(1)创建映射配置文件
注:创建包时com.baiyun,dao其实是创建了三级目录。而是目录时候,com.baiyun.dao只相当于一级目录。

(1)映射配置文件的mapper标签中namespace 属性的取值必须是Dao接口中的全限定类名
(2)映射配置文件的操作配置,id属性的取值必须是Dao接口的方法名。
当我们遵循了第1、第2点之后,我们在开发过程中就无须再写User Dao的实现类

在这里插入图片描述
代码:

<?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="Dao.IUserDao">
    <!--配置查询所有用户的SQL -->
    <select id="findAll" resultType="domain.User">
        select * from user
    </select>
</mapper>

注意:

IDEA也可以将Mapper文件放在source目录下即“java”文件夹下,但是idea的maven骨架不会编译src的java目录的xml文件,所以在Mybatis的配置文件中会报找不到xml文件!此时需要在pom文件中新加一个build提示编译器,把以下代码复制到pom文件中即可:

<build>
    <resources>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.xml</include>
            </includes>
        </resource>
    </resources>
</build>

2.5、 加入log4j配置文件
因为在接下来的入门案例中会用到log4j和Junit,所以之前没有在pom文件中导入log4jJunitjar包的童鞋导入一下。
(1)并且加入log4j的配置文件:
在这里插入图片描述
代码:

# Set root category priority to INFO and its only appender to CONSOLE.
#log4j.rootCategory=INFO, CONSOLE            debug   info   warn error fatal
log4j.rootCategory=debug, CONSOLE, LOGFILE

# Set the enterprise logger category to FATAL and its only appender to CONSOLE.
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE

# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n

# LOGFILE is set to be a File appender using a PatternLayout.
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=d:\axis.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n

具体log4J的配置详解百度去,这里不多说。

(2)在test包下创建一个测试类:
在这里插入图片描述
在测试类中写入代码:

package test;
import Dao.IUserDao;
import domain.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
//入门案例
public class MyBatisTest {
    public static void main(String[] args) throws IOException {
        //1、读取配置文件
        InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");

        //2、创建sqlSessionFactory工厂
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory factory = builder.build(in);

        //3、使用工厂生成sqlSession对象
        SqlSession sqlSession = factory.openSession();

        //4、使用SqlSession创建Dao接口的代理对象
        IUserDao userDao = sqlSession.getMapper(IUserDao.class);

        //5、使用代理对象执行方法
        List<User> users = userDao.findAll();
        for(User user : users){
            System.out.println(user);
        }
        //6、释放资源
        sqlSession.close();
        in.close();
    }
}

说明:(1)与数据库的每一次交互都是通过SqlSession对象进行交互的,所以需要每次执行完之后完毕。
(2)SqlSession和Connection对象一样都是线程不安全的,每次使用都需要创建SqlSession对象,如果作为全局变量重复使用会引发现成安全问题。

代码分析:
在这里插入图片描述

当运行代码的时候报错:
在这里插入图片描述

解决方法:
https://blog.csdn.net/qq_22076345/article/details/82392236

踩坑一:
在这里插入图片描述
答案:

是因为找不到数据源导致报的错:

在这里插入图片描述
报这个错一般是MyBatis的配置文件错误导致。

踩坑三:查询出来的数据"地址"字段没有值:
在这里插入图片描述

解决方案:数据库中的字段要和bean类中的对象一 一对应,不能写错或省略下划线。

三、MyBatis全局配置文件

3.1、properties标签

  以上做了MyBatis入门案例之后,发现MyBatis中的数据配置其实是硬编码。也就是每次想要修改数据库链接的时候,需要停止项目,修改配置,重新打包,部署等步骤,不够灵活。下面我们通过使用配置文件来记录数据库的链接信息,然后通过配置文件中的properties标签读取配置信息。

<properties>标签可以引入外部其他配置文件(properties后缀)的内容。
其中有两个属性:
(1)resource:引入类路径下的资源
(2)url :引入网络路径或硬盘下的资源

1、新建一个数据库properties文件:
在这里插入图片描述
内容:

#MySQL数据库连接信息
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test
jdbc.username=root
jdbc.password=123456

2、引入标签:
在这里插入图片描述
再运行结果即可。

3.2、settings标签

  这个标签是MyBatis中极为重要的调整设置,可设置的参数有很多,它们会改变MyBatis运行时的行为,比如自动映射,驼峰命名映射,级联规则,是否开启缓存,执行器类型等等。

<settings>标签包含很多设置项。settings:用来设置每一个设置项
name:设置项名称
value:设置项取值(true或false,每一个项都有默认值)

比如:我们数据表中有个字段是stu_name,而Bean对象中写的是stuName,此时只需要设置如下驼峰命名设置项就能MyBatis就能正常映射:
在这里插入图片描述
类似的设置项还很多:

<settings>
    <setting name="cacheEnabled" value="true"/>
    <setting name="lazyLoadingEnabled" value="true"/>
    <setting name="multipleResultSetsEnabled" value="true"/>
    <setting name="useColumnLabel" value="true"/>
    <setting name="useGeneratedKeys" value="false"/>
    <setting name="autoMappingBehavior" value="PARTIAL"/>
    <setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
    <setting name="defaultExecutorType" value="SIMPLE"/>
    <setting name="defaultStatementTimeout" value="30"/>
    <setting name="defaultFetchSize" value="200"/>
    <setting name="safeRowBoundsEnabled" value="false"/>
    <setting name="mapUnderscoreToCamelCase" value="false"/>
    <setting name="localCacheScope" value="SESSION"/>
    <setting name="jdbcTypeForNull" value="OTHER"/>
    <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
</settings>

说明如下:
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.3、typeAliases标签

3.3.1、typeAlias标签

<typeAliasos>是MyBatis中的别名处理器

如果MyBatis中的Mapple文件在写SQL的时候经常用到一个返回值类型,可以使用别名处理器来配置返回值类型。
如:
在这里插入图片描述
全局配置文件中加入别名处理器:
在这里插入图片描述

修改mapper映射文件:
在这里插入图片描述
此时也能正常运行。

3.3.2、package标签

<package>是批量取别名标签。为某个包下的所有类批量取别名
name:指定包名(为当前包及其以下所有后代包中的每一个类取默认别名,即类名小写。别名不区分大小写)

在这里插入图片描述

通常标签是配合@Alias注解一起使用的,`@Alias是不能单独>使用的

@Alias用于Bean对象类头,用于给指定类取别名。
在这里插入图片描述
修改Mapper文件返回值类型:
在这里插入图片描述
此时同样可以正常运行。

对于MyBatis中的返回值类型,个人建议不要取别名,直接使用包名.类型作为返回值类型更好,因为(1)可以使用Ctrl + 鼠标左键 点进入查看实体属性。(2)MyBatis为基本类型和部分常用的引用类型取好了别名,所以引用的取好的别名会出现报错。

MyBatis默认已注册别名:

别名 映射的类型
_byte byte
_long long
_short short
_int int
_integer int
_double double
_float float
_boolean boolean
string String
byte Byte
long Long
short Short
int Integer
integer Integer
double Double
float Float
boolean Boolean
date Date
decimal BigDecimal
bigdecimal BigDecimal
map Map

SQL映射文件:

    <!-- 
        指定 resultType 返回值类型时 String 类型的,
        string 在这里是一个别名,代表的是 java.lang.String 

        对于引用数据类型,都是将大写字母转小写,比如 HashMap 对应的别名是 'hashmap'
        基本数据类型考虑到重复的问题,会在其前面加上 '_',比如 byte 对应的别名是 '_byte'
    -->
    <select id="getEmpNameById" resultType="string">
        select username from t_employee where id = #{id}
    </select>

3.4、typeHandlers标签

typeHandlers是类型处理器。是java类型和数据库类型 一 一映射的一个桥梁。比如将java中string类型保存到数据库varchar中,对String和varchar进行一个适配。再比如将数据库返回结果集中的int与java中的Integer类型进行一个适配。
typeHandlers类型处理器后面再做详细的说明,在这只作为一个概念了解。

3.5、plugins

MyBatis的插件是一个非常强大的功能,需要等熟悉了MyBatis的整个运行流程之后再做介绍。

MyBatis运行我们利用插件机制拦截到数据库执行SQL的一些步骤。

3.6、environments标签

environments是环境配置标签,在此环境配置标签中,MyBatis可以配置多种数据源环境。
<environments>使用default属性指定使用某个环境
 —<environment>:配置具体环境信息
  —<transactionManager>事务管理器。配置事务类型
  —<dataSource>数据源。
在这里插入图片描述
其中<transactionManager>事务管理器有三种取值:
(1)JDBC:使用JDBC数据库的方式进行事务回滚,提交控制。
(2)MANAGED:使用JAVAEE服务器的方式进行事务的控制。
(3)自定义事务控制:代码参考jdbc或MANAGED方式。

-<dataSource>数据源:
(1)UNPOOLED:不使用连接池的技术。每次CRUD操作,都会从数据库中拿一次连接。不从连接池中拿连接。
(2)POOLED:使用连接池技术。
(3)JNDI:JNDI(java nameing and drectory interface),是一组在Java应用中访问命名和服务的API将对象和名称联系起来,使得可以通过名称访问并获取对象。
(4)自定义数据源。(如果想使用C3P0或DBCP连接池,可以自定义实现,实现接口DataSourceFactory接口)

3.7、databaseldProvider标签

MyBatis可以执行不同的SQL语句,通过该标签标识不同的数据库厂商,从而让MyBatis数据库来执行不同数据库厂商的SQL。

databaseldProvider支持多数据库。
 —type:数据库厂商标识(驱动)。

需求:目前mySQL有一张user表,Oracle中也有一张user表,如何实现使用Mapper文件中的同一个SQL的id来查不同库中的数据。

(1)使用databaseldProvider标签:
在这里插入图片描述
(2)配置文件中增加Oracle的连接信息:
在这里插入图片描述
(3)配置Oracle的数据库连接信息:
在这里插入图片描述

(4)mapper文件中增加数据库标识:
在这里插入图片描述
此时在全局配置文件中切换不同数据库运行则不行不同的SQL。

3.8、mappers标签

mappers标签是将sql映射到全局配置中。

mapper
--resource:引用类路径下的sql映射文件(注册文件)
--url:引用网络路径或磁盘路径下的sql映射文件(注册文件)
--class:引用(注册)接口
方法一:有sql映射文件,文件名称必须和(Dao)接口名相同,且必须和(Dao)接口文件放在一个目录下
方法二:没有sql映射文件,所有的SQL都是利用注解写在Dao接口上

以上例子我们就是用resource注册文件的方式做的,下面我们演示一下使用注册接口的方式做法。
步骤:
(1)在IUserDao接口文件中加入注解和SQL
在这里插入图片描述
(2)在MyBatis全局配置文件中修改文件注册为接口注册:
在这里插入图片描述
(3)测试:
在这里插入图片描述
综上所述:

推荐使用SQL映射文件和Dao接口配置文件分为这种,因为设置到比较负责的SQL的时候不方便维护。

<mappers>标签中也可以使用package进行批量注册
标签中的三种注册方式参考文章
https://blog.csdn.net/weixin_43951534/article/details/90416363

全局配置文件结构:
(MyBatis全局配置文件中存在的标签必须按以下顺序来写)

configuration 配置
  properties 属性:可以加载properties配置文件的信息
  settings 设置:可以设置mybatis的全局属性
  typeAliases 类型命名
  typeHandlers 类型处理器
  objectFactory 对象工厂
  plugins 插件
  environments 环境
    environment 环境变量
      transactionManager 事务管理器
      dataSource 数据源
  databaseIdProvider 数据库厂商标识
  mappers 映射器

写的好的文章推荐:https://www.cnblogs.com/liubin1988/p/8555982.html

四、MyBatis映射文件

4.1、Mapper常用标签

先说一下Mapper配置文件的配置:

<?xml version="1.0" encoding="UTF-8" ?>   
<!DOCTYPE mapper   
PUBLIC "-//ibatis.apache.org//DTD Mapper 3.0//EN"  
"http://ibatis.apache.org/dtd/ibatis-3-mapper.dtd"> 
 
<!-- mapper 为根元素节点, 一个namespace对应一个dao -->
<mapper namespace="com.dao.UserDao">
 
    <insert
      <!-- 1. id (必须配置)
        id是命名空间中的唯一标识符,可被用来代表这条语句。 
        一个命名空间(namespace) 对应一个dao接口, 
        这个id也应该对应dao里面的某个方法(相当于方法的实现),因此id 应该与方法名一致 -->
      
      id="addUser"
      
      <!-- 2. parameterType (可选配置, 默认为mybatis自动选择处理)
        将要传入语句的参数的完全限定类名或别名, 如果不配置,mybatis会通过ParameterHandler 根据参数类型默认选择合适的typeHandler进行处理
        parameterType 主要指定参数类型,可以是int, short, long, string等类型,也可以是复杂类型(如对象) -->
      
      parameterType="user"
      
      <!-- 3. flushCache (可选配置,默认配置为true)
        将其设置为 true,任何时候只要语句被调用,都会导致本地缓存和二级缓存都会被清空,(对与插入、更新和删除语句flushCache默认值是true,查询的默认值是false),表示任何时候语句被调用,都不会去清空本地缓存和二级缓存。
文章推荐:[https://blog.csdn.net/jacabe/article/details/80008879](https://blog.csdn.net/jacabe/article/details/80008879)
 -->
      
      flushCache="true"
      
      <!-- 4. statementType (可选配置,默认配置为PREPARED)
        STATEMENT,PREPARED 或 CALLABLE 的一个。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。 -->
      
      statementType="PREPARED"
      
      <!-- 5. keyProperty (可选配置, 默认为unset)
        (仅对 insert 和 update 有用)唯一标记一个属性,MyBatis 会通过 getGeneratedKeys 的返回值或者通过 insert 语句的 selectKey 子元素设置它的键值,默认:unset。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。 -->
      
      keyProperty=""
      
      <!-- 6. keyColumn     (可选配置)
        (仅对 insert 和 update 有用)通过生成的键值设置表中的列名,这个设置仅在某些数据库(像 PostgreSQL)是必须的,当主键列不是表中的第一列的时候需要设置。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。 -->
      
      keyColumn=""
      
      <!-- 7. useGeneratedKeys (可选配置, 默认为false)
        (仅对 insert 和 update 有用)这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键(比如:像 MySQL 和 SQL Server 这样的关系数据库管理系统的自动递增字段),默认值:false。  -->
      
      useGeneratedKeys="false"
      
      <!-- 8. timeout  (可选配置, 默认为unset, 依赖驱动)
        这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为 unset(依赖驱动)。 -->
      timeout="20">
 
    <update
      id="updateUser"
      parameterType="user"
      flushCache="true"
      statementType="PREPARED"
      timeout="20">
 
    <delete
      id="deleteUser"
      parameterType="user"
      flushCache="true"
      statementType="PREPARED"
      timeout="20">
</mapper>

MyBatis支持使用增(insert)、删(delete)、查(select)、改(update)标签

例如:DAO接口定义:

public Interface IUserDao{
	public void addUser(User user); 	    //增加用户
	public void delUserById(Integer id);    //删除用户
	public void queryUserById(Integer id);  //查询用户
	public void updateUserById(Integer id); //修改用户
}

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

<mapper namespace="Dao.IUserDao" >
	<!--新增、修改、删除的SQL注意:
		parameterType如若不写,则根据参数类型返回默认
		增、删、改中没有resultType属性。
-->
	<insert id="addUser" parameterType="domain.User">
		insert into user(id,name,sex,phone,address)
		values(#{id},#{name},#{sex},#{phone},#{address})
	</insert>
	
	<!--删除用户SQL -->
	<delete id="delUserById">
		delete from user where id=#{id}
	</delete>

	<!--修改用户SQL -->
	<update id="updateUserById">
		update user set name=#{name}, sex=#{sex}, phone=#{phone}, address=#{address}
		where id=#{id}
	</update>
	
    <!--查询用户的SQL -->
    <select id="queryUser">
        select * from user where id=#{id}
    </select>
</mapper>

注意

1、CRUD中的parameterType可以省略不写,默认不写mybatis会通过ParameterHandler 根据参数类型默认选择合适的typeHandler进行处理(默认别名)。其中resultType在crud中是不存在的。

2、在crud中resultType属性是不存在的。但是定义接口的时候MyBatis允许直接定义Integer、Long、Boolean作为返回值类型
例如:
public Integer addUser(User user); //增加用户
public Long update UserById(Integer id); //修改用户
public Boolean delUserById(Integer id); //删除用户
public Map<String, Object> getEmpAsMapById(Integer id); //根据 id 查询信息,并把结果信息封装成 Map

对应映射文件可写成:

<insert id="addUser" parameterType=”java.lang.Integer” >

<insert id="addUser" parameterType=”int” >

再比如:

<select id="getEmpAsMapById" resultType="map"> </select>

<select id="addUser" parameterType=”int” resultType="int">

4.2、selectKey标签

注:

如果使用MySql数据库的主键自增属性,在MyBatis中insert以后想要获取MySQL自增主键,只需要将useGeneratedKeys设置成true,且设置keyProperty一个bean属性字段来接收返回的主键即可。
例如:
<insert id="addUser" parameterType=“bean.user” useGeneratedKeys=“true” keyProperty=“stuID”>
</insert>

Oracle没有自增主键功能,如果是Oracle想要拿到返回的主键,需要在Insert中使用selectKey标签,<selectKey>常用于oracle的insert语句中,如下:

 <insert id="addUser" parameterType="bean.user">
 	<selectKey keyProperty="userID" order="AFTER" resultType="Integer">
 		select userID from users A where A.userID=#{id}   
 	</selectKey>
 	insert into users(userID, name, sex)
 	values(#{id}, #{name}, #{sex}) 
</insert>

order="AFTER"运行程序:
  先执行插入的SQL
  再运行selectKey查询id的SQL,查出id值封装给bean字段
order="before"运行程序:
  先运行selectKey查询id的SQL,查出id值封装给bean字段
  后运行插入的SQL
keyProperty=“userID”
将查出的主键id值封装给bean字段

详细可参考文章:https://blog.csdn.net/joyksk/article/details/76771386?utm_source=distribute.pc_relevant.none-task

4.3、Mapper文件参数处理问题

4.3.1、单个参数和多个参数处理问题

  Dao接口中传递单个参数和多个参数,MyBatis中的Mapper文件分别是怎么处理的呢?

1、单个参数处理。
  当接口中的参数只有一个的时候,mapper文件不做特殊处理,直接使用#{参数名}来取值即可。

2、多个参数处理
  当接口中的参数为多个的时候,MyBatis会将多个参数封装成一个map,其中map中的参数1,参数2,…分别为key:param1,param2…(或者写参数索引 0,1,2…也可以。)

mapper取值:#{param1}#{param2}

例如:

Dao接口:public Employee getEmp(Integer id, String name);

mapper文件正确取值:
<!--查询员工的SQL -->
<select id="queryUser">
  select * from emp where id=#{param1} and name=#{param2}
  <!--或id=#{0} and name=#{1}也可以-->
</select>
这种取值方法虽然可以取到参数值,但是看上去不容易理解,下面我们通过@Param参数注解方式完成。

步骤:
(1)修改Dao接口为:

public Employee getEmp(@Param("id")Integer id, @Param("name")String name);

(2)Mapper取值:

<!--查询员工的SQL -->
<select id="queryUser" resultType="com.emp">
  select * from emp where id=#{id} and name=#{name}
</select>
所以实际开发中:
如果传入的多个参数都是bean对象的属性字段(数据模型),我们可以直接传入Bean(pojo)
如果传入的多个参数不是bean对象的属性字段(数据模型),我们可以封装成map传入

例如:
(1)修改Dao接口为:

public Employee getEmp(Map<String, Object> map);

(2)Mapper取值:

<!--查询员工的SQL -->
<select id="queryUser" resultType="com.emp">
  select * from emp where id=#{id} and name=#{name}
</select>

如果传入的多个参数不是bean对象的属性字段(数据模型),且会被重复用到,推荐编写一个TO(Transfer object)数据传输对象:例如分页对象Page

**思考:根据Dao接口中的参数类型来取值
(1) public Emp getEmp(@Param(“id”)Integer id, String name);
取值:id=#{id}或id=#{param1}  name=#{param2}

(2) public Emp getEmp(Integer id, @Param(“e”)Emp emp);
取值:id=#{param1}
   name=#{param2.name}或name=#{e.name}

(3) public Emp getEmpById(List<Integer> ids);
要求取出第一个id的值,该怎么取呢?
拓长:
  如果参数类型是Collection(包括List、Set)类型或者是数组,MyBatis也会特殊处理。MyBatis也是把List或数组封装在map中。
key:collection(collection),如果是List还可以使用list,数组可以使用array
所以正确取值是 id=#{list[0]}

4.3.2、“#”和“$”参数处理区别

#{}${}用于获取map中的值或pojo对象属性值。
区别:
   #{}:是以预编译的形式,将参数设置到sql语句中。能够很大程度防止sql注入;

#将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号。如:order by #user_id#,如果传入的值是111,那么解析成sql时的值为order by “111”, 如果传入的值是id,则解析成的sql为order by “id”.

   ${}:取出的值直接拼接在sql语句中,$方式无法防止Sql注入;

$将传入的数据直接显示生成在sql中。如:order by $user_id$,如果传入的值是111,那么解析成sql时的值为order by user_id, 如果传入的值是id,则解析成的sql为order by id.
= = = = M y B a t i s 使 o r d e r b y 方式一般用于传入数据库对象,例如传入表名,字段名。== ==MyBatis排序时使用order by动态参数时需要注意,用 而不是#
比如分表和排序问题:
  select * from ${year}_salary where …;
  select * from tb1_employee order by ${f_name} ${order};

其中#{}还支持参数位置属性:
javaType、jdbcType、mode(存储过程)、numericScale(保留两位小数)、resultMap、TypeHandle、
jdbcTypeName

例如在Oracle中有些字段不是必填时在用户使用的时候会出现数据null的情况。这个时候在Oracle中是无法进行插入的。

JDBC Type Java Type
CHAR String
VARCHAR String
LONGVARCHAR String
NUMERIC java.math.BigDecimal
DECIMAL java.math.BigDecimal
BIT boolean
BOOLEAN boolean
TINYINT byte
SMALLINT short
INTEGER INTEGER
BIGINT long
REAL float
FLOAT float
VARCHAR double
DOUBLE double
BINARY byte[]
DATE java.sql.Date
TIME java.sql.Time
TIMESTAMP java.sql.Timestamp
CLOB Clob
BLOB Blob
ARRAY Array

在Mybatis也明文建议在映射字段数据时需要将JdbcType属性加上。这样相对来说是比较安全的。
以下情况是在保证了前四种是不能为空的前提下,而后面几项为空时也不至于程序报错。

<insert id="saveRole">
    insert into role_p values (
        #{roleId},
        #{name},
        #{remarks},
        #{orderNo},
        #{createBy,jdbcType=VARCHAR},
        #{createDept,jdbcType=VARCHAR},
        #{createTime,jdbcType=DATE},
        #{updateBy,jdbcType=VARCHAR},
        #{updateTime,jdbcType=DATE}
    )
</insert>

Mybatis中javaType和jdbcType对应和CRUD例子

<resultMap type="java.util.Map" id="resultjcm">
  <result property="FLD_NUMBER" column="FLD_NUMBER" javaType="double" jdbcType="NUMERIC"/>
  <result property="FLD_VARCHAR" column="FLD_VARCHAR" javaType="string" jdbcType="VARCHAR"/>
  <result property="FLD_DATE" column="FLD_DATE" javaType="java.sql.Date" jdbcType="DATE"/>
  <result property="FLD_INTEGER" column="FLD_INTEGER"  javaType="int" jdbcType="INTEGER"/>
  <result property="FLD_DOUBLE" column="FLD_DOUBLE"  javaType="double" jdbcType="DOUBLE"/>
  <result property="FLD_LONG" column="FLD_LONG"  javaType="long" jdbcType="INTEGER"/>
  <result property="FLD_CHAR" column="FLD_CHAR"  javaType="string" jdbcType="CHAR"/>
  <result property="FLD_BLOB" column="FLD_BLOB"  javaType="[B" jdbcType="BLOB" />
  <result property="FLD_CLOB" column="FLD_CLOB"  javaType="string" jdbcType="CLOB"/>
  <result property="FLD_FLOAT" column="FLD_FLOAT"  javaType="float" jdbcType="FLOAT"/>
  <result property="FLD_TIMESTAMP" column="FLD_TIMESTAMP"  javaType="java.sql.Timestamp" jdbcType="TIMESTAMP"/>
 </resultMap>

MyBatis好帖推荐https://blog.csdn.net/hellozpc/article/details/80878563

发布了22 篇原创文章 · 获赞 16 · 访问量 2903

猜你喜欢

转载自blog.csdn.net/qq_25083447/article/details/103811203