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目录下(即main文件夹的“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默认已注册别名:

别名映射的类型
_bytebyte
_longlong
_shortshort
_intint
_integerint
_doubledouble
_floatfloat
_booleanboolean
stringString
byteByte
longLong
shortShort
intInteger
integerInteger
doubleDouble
floatFloat
booleanBoolean
dateDate
decimalBigDecimal
bigdecimalBigDecimal
mapMap

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动态参数时需要注意,用 方式一般用于传入数据库对象,例如传入表名,字段名。====MyBatis排序时使用orderby动态参数时需要注意,用而不是#
比如分表和排序问题:
  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 TypeJava Type
CHARString
VARCHARString
LONGVARCHARString
NUMERICjava.math.BigDecimal
DECIMALjava.math.BigDecimal
BITboolean
BOOLEANboolean
TINYINTbyte
SMALLINTshort
INTEGERINTEGER
BIGINTlong
REALfloat
FLOATfloat
VARCHARdouble
DOUBLEdouble
BINARYbyte[]
DATEjava.sql.Date
TIMEjava.sql.Time
TIMESTAMPjava.sql.Timestamp
CLOBClob
BLOBBlob
ARRAYArray

在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

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值