————————————————————————————————————————
笔记
————————————————
- 提问:Mapper中怎么传递多个参数?
第一种(个人不推荐)
Public UserselectUser(String name,String area);
//对应的xml,#{0}代表接收的是dao层中的第一个参数,#{1}代表dao层中第二参数,更多参数一致往后加即可。
<select id="selectUser"resultMap="BaseResultMap">
select * fromuser_user_t whereuser_name = #{0} anduser_area=#{1}
</select>
————————
第二种:@Param
import org.apache.ibatis.annotations.param;
public interface usermapper {
user selectuser(@param(“username”) string username,
@param(“hashedpassword”) string hashedpassword);
}
<select id=”selectuser” resulttype=”user”>
select id, username, hashedpassword
from some_table
where username = #{username}
and hashedpassword = #{hashedpassword}
</select>
————————————————
- 提问:IDEA中操作mybatis时,怎样让IDE打印执行的SQL语句?
application.yml
mybatis:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
一般有这个需求都是为了验证结合MyBatis + Redis时:程序有无去DB查询;
如果是此需求的话,我认为有另一个办法可更优雅地取代打印SQL地行为;
实现逻辑一般是:
1.先去Redis查数据;
2.没有?再去DB查;
3.判空,数据存入Redis;
在第二步时输出一句:"fresh value from DB id:"+id
就可知有无去DB查询;
————————————————
————————————————
————————————————
————————————————————————————————————————
MyBatis 3.4.1
MyBatis 本是apache的一个开源项目iBatis,2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis;2013年11月迁移到Github;
iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的【持久层框架】;
iBATIS提供的持久层框架包括SQL Maps和Data Access Objects(DAOs);
当前,最新版本是MyBatis 3.5.2 ,其发布时间是2019年7月15日;
————————————————————
- 提问:持久化层框架?怎么理解
跟数据库交互的框架;
————————————————————
- 提问:你还知道哪些跟数据库交互的技术?
原生的JDBC:DBUtils的QueryRunner;
Spring提供了一个ORM小工具:JdbcTemplate;
Hibernate:全自动ORM(Object Relation Mapping)框架;
————————————————————
- 提问:小工具和框架有什么区别?
小工具和框架的差别是很大的;
小工具:
功能单一,仅执行SQL语句;
SQL语句硬编码高耦合在Java代码里(SQL语句优化后,在代码里一句句换掉,还要重新编译、打包、部署、运行,是很麻烦的);
框架:
是一个整体解决方案,跟DB交互不止执行SQL语句这么简单,还要考虑如何事物控制?如何实现查询缓存?部分字段映射等等;
————————————————————
- 提问:JDBC流程是什么?
编写SQL、预编译、设置参数、执行SQL、封装结果;
————————————————————
- 提问:Hibernate流程是什么?
全自动ORM(Object Relation Mapping)框架;
(当然也要经过JDBC这几步)
Hibernate最大主治:消除SQL,他希望开发人员不懂SQL也能成功操作;
————————————————————
- 提问:MyBatis流程是什么?
————————————————————————————————————————
最近更新: 2019/07| 版本: 3.5.2
https://github.com/mybatis/mybatis-3/releases
————————————————————————————————————————
配置数据源:Druid
https://blog.csdn.net/weixin_42915286/article/details/99664260
————————————————————————————————————————
POM
<!-- MySQL -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.17</version>
</dependency>
<!-- MyBatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.0</version>
</dependency>
<!-- Junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
————————————————————————————————————————
入门案例:XML+无接口(老版本)【不推荐】
注:
因为此入门案例会指定mybatis-config.xml为全局配置文件;
所以此时如果把DB/MyBatis属性定义在application.yml中会无法读取;
应该把属性都定义在指定的mybatis-config.xml中;
无接口模式的最大特点:Mapper.xml的namespace
可以随便命名
注:此入门案例不需要配置任何application.yml信息
无Mapper接口,所以Mapper.xml中的namespace是任意名;亦不需要Mapper接口实现
————————————————————
Entity:
private Integer id;
private String lastName;
private String email;
private String gender;
SETTER+GETTER
TOSTRING()
有参构造器(方便之后运行SQL时添加数据)
无参构造器(有了有参构造器就要有无参,好习惯)
————————————————————
映射文件 EmployeeMapper.xml
<?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="com.yau.sb_mybatis.EmployeeMapper">
<select id="selectEmp" resultType="com.yau.sb_mybatis.Entity.Employee">
select *
from tbl_employee
where id = #{id}
</select>
</mapper>
————————————————————
MyBatis全局配置类:mybatis-config.xml
因为无application.yml,所以driver、URL、username、password都硬编码在内;
注意mapper source的填写,否则空指针异常;
mapper.xml一定要定义在其中,否则测试类会报错IOException;
因为采用了驼峰命名法(DB:last_name,程序:lastName),所以要开启mapUnderscoreToCamelCase;
<?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>
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis?characterEncoding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="12345678"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="Mapper/EmployeeMapper.xml"/>
</mappers>
</configuration>
————————————————————
测试类
@RunWith(SpringRunner.class)
@SpringBootTest
public class MybatisAppTests {
public class MybatisAppTests {
@Test
public void contextLoads() throws IOException {
String resource = "mybatis-config.xml";
InputStream in = Resources.getResourceAsStream(resource); // exception
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
SqlSession openSession = sqlSessionFactory.openSession();
try{
Employee employee = openSession.selectOne("com.yau.sb_mybatis.EmployeeMapper.selectEmp",1);
System.out.println(employee);
}finally{
in.close();
openSession.close();
}
}
}
返回DB中ID=1的Employee信息:
Employee{id=1, lastName='Sam', gender=0, email='sam@123.com'}
————————————————————————————————————————
入门案例:XML+有接口(推荐)
注:
因为此入门案例会指定mybatis-config.xml为全局配置文件;
所以此时如果把DB/MyBatis属性定义在application.yml中会无法读取;
应该把属性都定义在指定的mybatis-config.xml中;
注:
此入门案例不需要配置任何application.yml信息;
不需要Mapper接口实现(Mapper接口对应Mapper.xml来实现);
无接口模式的最大特点:
1.Mapper.xml的namespace
不可以随便命名,必须对应Mapper接口全路径
2.且Mapper.xml的方法ID要和Mapper接口中的方法名字对应;
Entity
mybatis-config.xml
EmployeeMapper.xml
<?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="com.yau.sb_mybatis.Mapper.EmployeeMapper">
<select id="getEmpById" resultType="com.yau.sb_mybatis.Entity.Employee">
select *
from tbl_employee
where id = #{id}
</select>
</mapper>
EmployeeMapper 接口(新增)
public interface EmployeeMapper {
public Employee getEmpById(Integer id);
}
测试类
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;
@RunWith(SpringRunner.class)
@SpringBootTest
public class MybatisAppTests {
@Test
public void contextLoads() throws IOException {
InputStream in = Resources.getResourceAsStream("Mybatis/mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
SqlSession openSession = sqlSessionFactory.openSession();
try{
EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
Employee employee = mapper.getEmpById(1);
System.out.println(employee);
}finally{
in.close();
openSession.close();
}
}
}
- 提问:MyBatis接口式与非接口式相比有什么好处?
1.接口可规定【属性】的类型检查,比如规定了Integer就不能传String;
2.接口可规定【返回值】的检查;
3.接口是一种抽象,所以可以实现多种实现,比如除了可以用Mybatis,还可以用Hibernates等持久层框架;
- 总结
- 1.原生JDBC:DAO - DAOImpl;MyBatis:Mepper - Mapper.xml;
- 2.SqlSession相当于和DB的一次会话,用完必须关闭!
- 3.SqlSession底层是JDBC的Connection,非线程安全(线程不安全),不能定义成
private SqlSession sqlSession
,每次使用必须获取一个新的对象; - 4.Mapper接口不需要实现类,因为MyBatis会为该接口生成一个代理对象,把接口和XML进行绑定;
EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
- 5.两个重要配置文件:
(1).mybatis-config.xml
全局配置文件;
(可以不用全局配置文件,即把信息硬编码在测试类中)
(2).xxxMapper.xml
SQL映射文件;
(必须要有)
————————————————————————————
MyBatis注解备注
MyBatis注解备注
若使用注解版SQL;
Mapper接口方法里定义多个参数时,每个参数前要加上@Param("")
(但个参数可以不加)
@Select("select * from XXX where id = #{id} and sex = #{sex}")
Entity findById(@Param("id")int id,@Param("sex")int sex);
——————————
@Result({
@Result(column = "create_time",property = "createTime")
})
——————————
主键自增:
Mapper接口中方法前添加:
`@Options(userGeneratedKeys = true,keyProperty = "id",keyColumn="id")`
keyProperty 是项目中定义的属性;
keyColumn 是DB主键;
——————————
——————————
——————————
——————————————————————————————————————————
Application.yml配置版本
mybatis:
configuration:
map-underscore-to-camel-case: true #驼峰
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 打印执行的SQL语句
——————————————————————————————————————————
mybatis-config.xml 全局配置文件
(也有常见名:SqlMapConfig.xml)
官方文档:http://www.mybatis.org/mybatis-3/zh/configuration.html
————————————————————
dtd文件
我希望在编写全局配置文件时有提示,或者语法写错了有提醒;
在mybatis-config.xml表头中引入:dtd文件即可:http://mybatis.org/dtd/mybatis-3-mapper.dtd
;
作用:约束该XML中的语法规范;
该dtd文件对应Library中mybatis-3-mapper.dtd
————————————————————
自己总结的模版:
注意:
- 1.发现properties里的value无法引用
application.yml
的信息,建议硬编码;
但能引用application.properties
的信息,前提是加上一行<properties resource="application.properties"/>
- 2.发现mapper里只能指向一个个零散的xml,无法指向包:
<mapper package = ""/>
;
<?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>
<settings>
<setting name="cacheEnabled" value="false"/>
<setting name="mapUnderscoreToCamelCase" value="true"/>
<setting name="useGeneratedKeys" value="true"/>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/sb_shiro"/>
<property name="username" value="root"/>
<property name="password" value="12345678"/>
</dataSource>
</environment>
</environments>
<mappers>
<!--<mapper resource = ""/>-->
<mapper resource = "Mybatis/Mapper/UserMapper.xml"/>
<mapper resource = "Mybatis/Mapper/RoleMapper.xml"/>
<mapper resource = "Mybatis/Mapper/PermissionMapper.xml"/>
</mappers>
</configuration>
————————————————————
<properties>
(忽略)
不建议使用;此属性不能读取application.yml
的配置信息;
通常情况下建议不要配置他,因为这会影响MyBatis对属性的读取顺序,容易造成配置文件被覆盖;
MyBatis读取优先级:
优先级最高:parameterType
,即xxxMapper.xml里的属性;
优先级次高:resouce
或url
;(覆盖上条)
优先级最低:<properties>
定义的属性;(覆盖上条)
非入门案例的情况下,建议把配置动态参数都写在properties.yml中;
————————————————————
<settings>
(重要)
这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为;
不要乱配置;
一个配置完整的 settings 元素的示例
(配置非默认,已按个人喜好改动):
- 提问:mybatis某版本中,有些setting配置默认是开启的;当我们需开启某配置时,还需不需要多此一举,添加一个value为true的setting?
建议写;
即使某版本中默认开启,最好也显示地指定我们需要更改的配置的值,以防止mybatis版本更新带来的默认value的改变;(版本更新后,默认value本来为true,可能后来又变成false,带来混乱)
<settings>
<setting name="cacheEnabled" value="true"/>
<setting name="lazyLoadingEnabled" value="true"/> // 此两条配合完成:分步查询的延迟加载
<setting name="aggressiveLazyLoading" value="false"/> // 此两条配合完成:分步查询的延迟加载
<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="25"/>
<setting name="defaultFetchSize" value="100"/>
<setting name="safeRowBoundsEnabled" value="false"/>
<setting name="mapUnderscoreToCamelCase" value="true"/>
<setting name="localCacheScope" value="SESSION"/>
<setting name="jdbcTypeForNull" value="OTHER"/>
<setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
</settings>
——————————
useGeneratedKeys
(true/false
,默认false
)
允许 JDBC 支持自动生成主键,需要驱动兼容。
驱动兼容的意思是:需要配合支持自动生成记录主键的数据库,如:MySQL,SQL Server(Oracle不支持自增);
在执行添加记录之后可以获取到数据库自动生成的主键ID。
白话:
如:操作Insert方法时,由于DB:MySQL支持属性自增,给DB中ID属性配置了auto_increment后,DB经过MyBatis新增一条数据时,新增数据的ID会自增(与程序无关);
若我们在此Insert方法运行后配置马上返回数据信息,那么返回的ID会是NULL;
这是因为ID交给了DB自增,程序无法第一时间拿到ID,只能在之后的操作中获得;
如何第一时间返回自增的ID?
这时,我们需要首先在<settings>
中开启:<setting name="useGeneratedKeys" value="true"/>
(1).XML版时:在Mapper.xml的方法中配置useGeneratedKeys = "true" keyProperty="属性名"
;
(2).注解版:在方法前中配置@Options(userGeneratedKeys = true,keyProperty = "id")
——————————
useColumnLabel
(true/false
,默认true
)
使用列标签代替列名。
不同的驱动在这方面会有不同的表现, 具体可参考相关驱动文档或通过测试这两种不同的模式来观察所用驱动的结果。
——————————
mapUnderscoreToCamelCase
(true/false
,默认false
)
开启自动驼峰命名规则(camel case)映射;
比方:若开启了驼峰命名?数据库列名 user_name
(下划线)自动对应实体类中的userName
(驼峰命名)映射。
页面搜索:驼峰命名法 mapUnderscoreToCamelCase
——————————
cacheEnabled
(true/false
,默认true
)
全局地开启或关闭配置文件中的所有映射器已经配置的二级缓存,默认开启;
(一级缓存默认无法关闭,所以不用理)
页面搜索:二级缓存 使用&细节
——————————
——————————
——————————
lazyLoadingEnabled
(true/false
,默认false
)
分步查询时,【延迟加载】的全局开关;
(延迟加载 的前提是:分步查询)
当开启时,所有关联对象都会延迟加载。
特定关联关系中可通过设置fetchType属性来覆盖该项的开关状态。
白话:
比如Employee实体类中有另一个实体类Department的属性:private Department department;
每次查询Employee时,都会顺带把Department也查了出来;但我们有时不需Department信息,每次全查出来会浪费DB资源;
实现延迟加载,即可在查询Employee时控制:要不要查询其中的Department信息;
具体实现?页面搜索:resultMap 关联查询 分步查询 延迟加载
——————————
aggressiveLazyLoading
(true/false
,默认false
;版本3.4.1前默认开启)
当开启时,任何方法的调用都会加载该对象的所有属性。
否则,每个属性会按需加载(参考lazyLoadTriggerMethods)。
lazyLoadingEnabled
和aggressiveLazyLoading
配合完成:分步查询的延迟加载;
——————————
- 提问:
lazyLoadingEnabled
和aggressiveLazyLoading
的区别?如何配合一起用?
1.lazyLoadingEnabled: true
aggressiveLazyLoading: true
开启延迟加载,不管级联属性是否被调用都会加载进来(按照层次);
2.lazyLoadingEnabled: true
aggressiveLazyLoading: false
开启延迟加载;
未使用级联属性时,不会加载级联属性;
主动调用级联属性时,加载级联属性;
白话:级联属性再调用的时候才会加载;
(比如:Employee中级联属性是Department department
)
——————————
——————————
——————————
multipleResultSetsEnabled
(true/false
,默认true
)
是否允许单一语句返回多结果集(需要兼容驱动)。
——————————
autoMappingBehavior
(NONE, PARTIAL,FULL
,默认PARTIAL
)
指定 MyBatis 应如何自动映射列到字段或属性,是一个容易被忽略的属性;
<setting name="autoMappingBehavior" value="partial"/>
(默认):自动映射没有定义嵌套结果集映射的结果集,唯一要求是列名和javaBean属性名一致;
<setting name="autoMappingBehavior" value="full"/>
:自动映射任意复杂的结果集(无论是否嵌套);
<setting name="autoMappingBehavior" value="none"/>
:取消自动映射;
——————————
autoMappingUnknownColumnBehavior
(NONE, WARNING, FAILING
,默认NONE
)
指定发现自动映射目标未知列(或者未知属性类型)的行为。
NONE: 不做任何反应;
WARNING: 输出提醒日志;('org.apache.ibatis.session.AutoMappingUnknownColumnBehavior’的日志等级必须设置为 WARN)
FAILING: 映射失败 (抛出 SqlSessionException);
——————————
defaultExecutorType
(SIMPLE,REUSE,BATCH
,默认SIMPLE
)
配置默认的执行器。SIMPLE 就是普通的执行器;REUSE 执行器会重用预处理语句(prepared statements); BATCH 执行器将重用语句并执行批量更新。
——————————
defaultStatementTimeout
设置超时时间,它决定驱动等待数据库响应的秒数。 任意正整数 Not Set (null)
defaultFetchSize 为驱动的结果集获取数量(fetchSize)设置一个提示值。此参数只可以在查询设置中被覆盖。 任意正整数 Not Set (null)
——————————
safeRowBoundsEnabled
允许在嵌套语句中使用分页(RowBounds)。如果允许使用则设置为false。 true | false False
——————————
safeResultHandlerEnabled
(true/false
,默认true
)
允许在嵌套语句中使用分页(ResultHandler)。如果允许使用则设置为false。
——————————
localCacheScope
(SESSION,STATEMENT
,默认SESSION
)
MyBatis 利用本地缓存机制(Local Cache)防止循环引用(circular references&#