文章目录
一、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文件中导入log4j 和Junitjar包的童鞋导入一下。
(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动态参数时需要注意,用 方式一般用于传入数据库对象,例如传入表名,字段名。====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 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