SSM_Mybatis_Day01(快速入门、映射文件概述、核心配置文件概述、相应API、代理开发方式、映射文件深入、数据类型的映射、列名和属性名不一致的时候的处理)
1. Mybatis
mybatis是一个ORM框架,持久化框架。
持久化 就是将数据永久的保存在一定的存储设备上。
Mybatis就是jdbc的升级版的框架;
框架:就是一个可以进行数据的jdbc操作的一个大的结构,半成品。
1.1原始jdbc操作(查询数据)
1.2原始jdbc操作(插入数据)
1.3 原始jdbc操作的分析
原始jdbc开发存在的问题如下:
①数据库连接创建、释放频繁造成系统资源浪费从而影响系统性能
②sql 语句在代码中硬编码,造成代码不易维护,实际应用 sql 变化的可能较大,sql 变动需要改变java代码。
③查询操作时,需要手动将结果集中的数据手动封装到实体中。插入操作时,需要手动将实体的数据设置到sql语句的占位符位置
应对上述问题给出的解决方案:
①使用数据库连接池初始化连接资源
②将sql语句抽取到xml配置文件中
③使用反射、内省等底层技术,自动将实体与表进行属性与字段的自动映射
1.4 什么是Mybatis
mybatis 是一个优秀的基于java的持久层框架,它内部封装了jdbc,使开发者只需要关注sql语句本身,而不需要花费精力去处理加载驱动、创建连接、创建statement等繁杂的过程。
mybatis通过xml或注解的方式将要执行的各种 statement配置起来,并通过java对象和statement中sql的动态参数进行映射生成最终执行的sql语句。
最后mybatis框架执行sql并将结果映射为java对象并返回。采用ORM思想解决了实体和数据库映射的问题,对jdbc 进行了封装,屏蔽了jdbc api 底层访问细节,使我们不用与jdbc api 打交道,就可以完成对数据库的持久化操作
2.Mybatis的快速入门
2.1 MyBatis开发步骤
1 使用maven创建一个普通的Java工程即可
2 引入mybatis的依赖
<?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">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.lanqiao</groupId>
<artifactId>mybatis_01</artifactId>
<version>1.0-SNAPSHOT</version>
<name>mybatis_01</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.4</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.36</version>
</dependency>
</dependencies>
</project>
3 创建数据库
使用最熟悉的emp表
/*
Navicat Premium Data Transfer
Source Server : mysql
Source Server Type : MySQL
Source Server Version : 50536
Source Host : localhost:3306
Source Schema : lanqiao
Target Server Type : MySQL
Target Server Version : 50536
File Encoding : 65001
Date: 20/04/2021 10:10:47
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for emp
-- ----------------------------
DROP TABLE IF EXISTS `emp`;
CREATE TABLE `emp` (
`empno` int(11) NOT NULL AUTO_INCREMENT,
`ename` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`job` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`mgr` int(11) NULL DEFAULT NULL,
`hiredate` date NULL DEFAULT NULL,
`sal` decimal(7, 2) NULL DEFAULT NULL,
`COMM` decimal(7, 2) NULL DEFAULT NULL,
`deptno` int(11) NULL DEFAULT NULL,
PRIMARY KEY (`empno`) USING BTREE,
INDEX `fk_emp`(`mgr`) USING BTREE,
CONSTRAINT `fk_emp` FOREIGN KEY (`mgr`) REFERENCES `emp` (`empno`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE = InnoDB AUTO_INCREMENT = 1014 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
-- ----------------------------
-- Records of emp
-- ----------------------------
INSERT INTO `emp` VALUES (1001, '甘宁', '文员', 1013, '2000-12-17', 8000.00, NULL, 20);
INSERT INTO `emp` VALUES (1002, '黛绮丝', '销售员', 1006, '2001-02-20', 16000.00, 3000.00, 30);
INSERT INTO `emp` VALUES (1003, '殷天正', '销售员', 1006, '2001-02-22', 12500.00, 5000.00, 30);
INSERT INTO `emp` VALUES (1004, '刘备', '经理', 1009, '2001-04-02', 29750.00, NULL, 20);
INSERT INTO `emp` VALUES (1005, '谢逊', '销售员', 1006, '2001-09-28', 12500.00, 14000.00, 30);
INSERT INTO `emp` VALUES (1006, '关羽', '经理', 1009, '2001-05-01', 28500.00, NULL, 30);
INSERT INTO `emp` VALUES (1007, '张飞', '经理', 1009, '2001-09-01', 24500.00, NULL, 10);
INSERT INTO `emp` VALUES (1008, '诸葛亮', '分析师', 1004, '2007-04-19', 30000.00, NULL, 20);
INSERT INTO `emp` VALUES (1009, '曾阿牛', '董事长', NULL, '2001-11-17', 50000.00, NULL, 10);
INSERT INTO `emp` VALUES (1010, '韦一笑', '销售员', 1006, '2001-09-08', 15000.00, 0.00, 30);
INSERT INTO `emp` VALUES (1011, '周泰', '文员', 1008, '2007-05-23', 11000.00, NULL, 20);
INSERT INTO `emp` VALUES (1012, '程普', '文员', 1006, '2001-12-03', 9500.00, NULL, 30);
INSERT INTO `emp` VALUES (1013, '庞统', '分析师', 1004, '2001-12-03', 30000.00, NULL, 20);
-- ----------------------------
-- Triggers structure for table emp
-- ----------------------------
DROP TRIGGER IF EXISTS `tri`;
delimiter ;;
CREATE TRIGGER `tri` AFTER DELETE ON `emp` FOR EACH ROW update stu set stu.age = stu.age + 100 where stu.sid = 1
;;
delimiter ;
SET FOREIGN_KEY_CHECKS = 1;
4 创建对应的实体
package cn.lanqiao.pojo;
import java.math.BigDecimal;
import java.util.Date;
/**
* @author Mr.Hu
* @create 2021/04/20
*/
public class Stu {
private Integer empno;
private String ename;
private String job;
private Date hiredate;
private BigDecimal sal;
public Stu() {
}
public Stu(String ename, String job, Date hiredate, BigDecimal sal) {
this.ename = ename;
this.job = job;
this.hiredate = hiredate;
this.sal = sal;
}
public Stu(Integer empno, String ename, String job, Date hiredate, BigDecimal sal) {
this.empno = empno;
this.ename = ename;
this.job = job;
this.hiredate = hiredate;
this.sal = sal;
}
public Integer getEmpno() {
return empno;
}
public void setEmpno(Integer empno) {
this.empno = empno;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
public Date getHiredate() {
return hiredate;
}
public void setHiredate(Date hiredate) {
this.hiredate = hiredate;
}
public BigDecimal getSal() {
return sal;
}
public void setSal(BigDecimal sal) {
this.sal = sal;
}
}
5 配置mybatis
<?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>
<!-- mybatis运行环境的 配置-->
<environments default="development">
<environment id="development">
<!-- 事务配置-->
<transactionManager type="JDBC"/>
<!-- 配置数据源-->
<dataSource type="POOLED">
<property name="driver" value="com.mysyql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/lanqiao"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!-- 配置sql的映射文件 一会再配-->
<mappers>
<mapper resource="cn/lanqiao/dao/StuDao.xml"/>
</mappers>
</configuration>
6.创建DAO接口
/**
* @author Mr.Hu
* @create 2021/04/20
*/
public interface StudentDao {
public void insertStu(Stu stu);
public List<Stu> selectAll();
}
7 配置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="cn.lanqiao.dao.StudentDao">
<select id="selectAll" resultType="cn.lanqiao.pojo.Stu">
select * from emp;
</select>
</mapper>
8 测试
public class StuDaoTest {
@Test
public void selelctAllTest() throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
// List<Stu> stuList = sqlSession.selectList("selectAll");
// System.out.println(stuList);
StudentDao dao = sqlSession.getMapper(StudentDao.class);
List<Stu> stuList = dao.selectAll();
System.out.println(stuList);
}
}
总结mybatis的使用步骤
1 引入依赖
2 创建实体
3 编写Dao接口
4 配置mybatis的著配置文件 mybatis-config.xml
5 配置dao的映射文件
6 完成测试 SqlSessionFactory
3. MyBatis的映射文件概述
**命名空间(Namespaces)**主要作用就是用来隔离sql的
一般情况下 namespace的值都等于其所对应的dao文件的全限定名
在有的情况下 很多人现在已经逐渐的将dao在mybatis命名为XXXMapper
3.1.myabtis使用的注意事项:
-
要注意我们导入的mybatis版本
-
在定义mapper接口的时候 其中的方法的取名
-
在定义接口的映射文件的时候 注意 文件的位置和名称 映射文件名必须和接口名完全一致
-
映射文件中 namesapce的值为mapper接口的全限定名
-
每条sql语句的id在同一个映射文件中必须唯一 对应接口的方法名
3.2.使用mybatis完成新增 删除 和更新 以及查询单个对象
定义接口
public interface StudentMapper {
public void insertStu(Stu stu);
public void updateStu(Stu stu);
public List<Stu> selectAll();
public void deleteStuById(Integer id);
public Stu selectStuById(Integer id);
}
在映射文件中 编写对应的SQL语句
<select id="selectAll" resultType="cn.lanqiao.pojo.Stu">
select * from emp;
</select>
<insert id="insertStu" parameterType="cn.lanqiao.pojo.Stu">
insert into emp(ename,job,hiredate,sal)values(#{ename},#{job},#{hiredate},#{sal});
</insert>
<delete id="deleteStuById" parameterType="int">
delete from emp where empno=#{empno}
</delete>
<update id="updateStu" parameterType="cn.lanqiao.pojo.Stu">
update emp set ename=#{ename},job=#{job} where empno=#{empno}
</update>
<select id="selectStuById" resultType="cn.lanqiao.pojo.Stu" parameterType="int">
select * from emp where empno=#{empno}
</select>
查看mybatis执行过程中对应的sql语句 mybatis的 日志
1 引入日志的依赖
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
2.配置日志
# 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
# 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
可以通过日志观察sql语句
测试
/**
* @author Mr.Hu
* @create 2021/04/20
*/
public class StuDaoTest {
private StudentMapper mapper = null;
private SqlSession sqlSession =null;
@Before
public void init() throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
sqlSession = sqlSessionFactory.openSession();
mapper = sqlSession.getMapper(StudentMapper.class);
}
@Test
public void selelctAllTest() throws IOException {
List<Stu> stuList = mapper.selectAll();
System.out.println(stuList);
}
@Test
public void insertTest(){
Stu stu = new Stu();
stu.setEname("tom");
stu.setJob("mybatis");
stu.setSal(new BigDecimal(1500.00));
stu.setHiredate(new Date());
mapper.insertStu(stu);//新增
sqlSession.commit();//手动提交事务
}
@Test
public void deleteTest(){
mapper.deleteStuById(1016);
sqlSession.commit();
}
@Test
public void updteTest(){
Stu stu = new Stu();
stu.setEmpno(1015);
stu.setEname("Lucy");
stu.setJob("Spring");
mapper.updateStu(stu);
sqlSession.commit();
}
@Test
public void selectOneTest(){
Stu stu = mapper.selectStuById(1015);
System.out.println(stu);
}
}
4. MyBatis核心配置文件概述
4.1.Properties
在resources下创建一个jdbc.properties
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/lanqiao
username=root
password=root
在mybatis-config.xml中使用
<configuration>
<properties resource="jdbc.properties"></properties>
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
<!-- mybatis运行环境的 配置-->
<environments default="development">
<environment id="development">
<!-- 事务配置-->
<transactionManager type="JDBC"/>
<!-- 配置数据源-->
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
4.2.setting
设置日志的实现框架log4j
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。 下表描述了设置中各项设置的含义、默认值等。
设置名 | 描述 | 有效值 | 默认值 |
---|---|---|---|
cacheEnabled | 全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。 | true | false | true |
lazyLoadingEnabled | 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。 | true | false | false |
aggressiveLazyLoading | 开启时,任一方法的调用都会加载该对象的所有延迟加载属性。 否则,每个延迟加载属性会按需加载(参考 lazyLoadTriggerMethods )。 | true | false | false (在 3.4.1 及之前的版本中默认为 true) |
multipleResultSetsEnabled | 是否允许单个语句返回多结果集(需要数据库驱动支持)。 | true | false | true |
useColumnLabel | 使用列标签代替列名。实际表现依赖于数据库驱动,具体可参考数据库驱动的相关文档,或通过对比测试来观察。 | true | false | true |
useGeneratedKeys | 允许 JDBC 支持自动生成主键,需要数据库驱动支持。如果设置为 true,将强制使用自动生成主键。尽管一些数据库驱动不支持此特性,但仍可正常工作(如 Derby)。 | true | false | False |
autoMappingBehavior | 指定 MyBatis 应如何自动映射列到字段或属性。 NONE 表示关闭自动映射;PARTIAL 只会自动映射没有定义嵌套结果映射的字段。 FULL 会自动映射任何复杂的结果集(无论是否嵌套)。 | NONE, PARTIAL, FULL | PARTIAL |
autoMappingUnknownColumnBehavior | 指定发现自动映射目标未知列(或未知属性类型)的行为。NONE : 不做任何反应WARNING : 输出警告日志('org.apache.ibatis.session.AutoMappingUnknownColumnBehavior' 的日志等级必须设置为 WARN )FAILING : 映射失败 (抛出 SqlSessionException ) | NONE, WARNING, FAILING | NONE |
defaultExecutorType | 配置默认的执行器。SIMPLE 就是普通的执行器;REUSE 执行器会重用预处理语句(PreparedStatement); BATCH 执行器不仅重用语句还会执行批量更新。 | SIMPLE REUSE BATCH | SIMPLE |
defaultStatementTimeout | 设置超时时间,它决定数据库驱动等待数据库响应的秒数。 | 任意正整数 | 未设置 (null) |
defaultFetchSize | 为驱动的结果集获取数量(fetchSize)设置一个建议值。此参数只可以在查询设置中被覆盖。 | 任意正整数 | 未设置 (null) |
defaultResultSetType | 指定语句默认的滚动策略。(新增于 3.5.2) | FORWARD_ONLY | SCROLL_SENSITIVE | SCROLL_INSENSITIVE | DEFAULT(等同于未设置) | 未设置 (null) |
safeRowBoundsEnabled | 是否允许在嵌套语句中使用分页(RowBounds)。如果允许使用则设置为 false。 | true | false | False |
safeResultHandlerEnabled | 是否允许在嵌套语句中使用结果处理器(ResultHandler)。如果允许使用则设置为 false。 | true | false | True |
mapUnderscoreToCamelCase | 是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。 | true | false | False |
localCacheScope | MyBatis 利用本地缓存机制(Local Cache)防止循环引用和加速重复的嵌套查询。 默认值为 SESSION,会缓存一个会话中执行的所有查询。 若设置值为 STATEMENT,本地缓存将仅用于执行语句,对相同 SqlSession 的不同查询将不会进行缓存。 | SESSION | STATEMENT | SESSION |
jdbcTypeForNull | 当没有为参数指定特定的 JDBC 类型时,空值的默认 JDBC 类型。 某些数据库驱动需要指定列的 JDBC 类型,多数情况直接用一般类型即可,比如 NULL、VARCHAR 或 OTHER。 | JdbcType 常量,常用值:NULL、VARCHAR 或 OTHER。 | OTHER |
lazyLoadTriggerMethods | 指定对象的哪些方法触发一次延迟加载。 | 用逗号分隔的方法列表。 | equals,clone,hashCode,toString |
defaultScriptingLanguage | 指定动态 SQL 生成使用的默认脚本语言。 | 一个类型别名或全限定类名。 | org.apache.ibatis.scripting.xmltags.XMLLanguageDriver |
defaultEnumTypeHandler | 指定 Enum 使用的默认 TypeHandler 。(新增于 3.4.5) | 一个类型别名或全限定类名。 | org.apache.ibatis.type.EnumTypeHandler |
callSettersOnNulls | 指定当结果集中值为 null 的时候是否调用映射对象的 setter(map 对象时为 put)方法,这在依赖于 Map.keySet() 或 null 值进行初始化时比较有用。注意基本类型(int、boolean 等)是不能设置成 null 的。 | true | false | false |
returnInstanceForEmptyRow | 当返回行的所有列都是空时,MyBatis默认返回 null 。 当开启这个设置时,MyBatis会返回一个空实例。 请注意,它也适用于嵌套的结果集(如集合或关联)。(新增于 3.4.2) | true | false | false |
logPrefix | 指定 MyBatis 增加到日志名称的前缀。 | 任何字符串 | 未设置 |
logImpl | 指定 MyBatis 所用日志的具体实现,未指定时将自动查找。 | SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING | 未设置 |
proxyFactory | 指定 Mybatis 创建可延迟加载对象所用到的代理工具。 | CGLIB | JAVASSIST | JAVASSIST (MyBatis 3.3 以上) |
vfsImpl | 指定 VFS 的实现 | 自定义 VFS 的实现的类全限定名,以逗号分隔。 | 未设置 |
useActualParamName | 允许使用方法签名中的名称作为语句参数名称。 为了使用该特性,你的项目必须采用 Java 8 编译,并且加上 -parameters 选项。(新增于 3.4.1) | true | false | true |
configurationFactory | 指定一个提供 Configuration 实例的类。 这个被返回的 Configuration 实例用来加载被反序列化对象的延迟加载属性值。 这个类必须包含一个签名为static Configuration getConfiguration() 的方法。(新增于 3.2.3) | 一个类型别名或完全限定类名。 | 未设置 |
shrinkWhitespacesInSql | 从SQL中删除多余的空格字符。请注意,这也会影响SQL中的文字字符串。 (新增于 3.5.5) | true | false | false |
defaultSqlProviderType | Specifies an sql provider class that holds provider method (Since 3.5.6). This class apply to the type (or value ) attribute on sql provider annotation(e.g. @SelectProvider ), when these attribute was omitted. | A type alias or fully qualified class name | Not set |
4.3.类型别名(typeAliases)
类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。
<typeAliases>
<!-- 一般使用类的简单类名来作为类的别名-->
<typeAlias type="cn.lanqiao.pojo.Stu" alias="Stu"/>
</typeAliases>
别名的第二种配置方式
<typeAliases>
<!-- 一般使用类的简单类名来作为类的别名-->
<!-- <typeAlias type="cn.lanqiao.pojo.Stu" alias="Stu"/>-->
<!-- 位于该包下的所有的类 均使用简单类名作为他的别名-->
<package name="cn.lanqiao.pojo"/>
</typeAliases>
以上方式为自定义类的别名配置,同时myabtis也为常用类默认设置了他们的别名
别名 | 映射的类型 |
---|---|
_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 |
object | Object |
map | Map |
hashmap | HashMap |
list | List |
arraylist | ArrayList |
collection | Collection |
iterator | Iterator |
- 对于Java中8中基本类型的别名为名称前加_
- String及8中基本类型包装类的别名 为他们对应的基本类型的名称 String 是首字母小写
- 集合、数组的别名都是首字母小写
4.4.环境配置(environments)
MyBatis 可以配置成适应多种环境,这种机制有助于将 SQL 映射应用于多种数据库之中, 现实情况下有多种理由需要这么做。例如,开发、测试和生产环境需要有不同的配置;或者想在具有相同 Schema 的多个生产数据库中使用相同的 SQL 映射。还有许多类似的使用场景。
不过要记住:尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。
<!-- mybatis运行环境的 配置 default指定当前使用的环境 每一个environment都必须具有唯一的id
default取值就来自于每一个environment的id值
-->
<environments default="development">
<environment id="development">
<!-- 事务配置-->
<transactionManager type="JDBC"/>
<!-- 配置数据源-->
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
<environment id="test">
<!-- 事务配置-->
<transactionManager type="JDBC"/>
<!-- 配置数据源-->
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
事务管理器(transactionManager)
在 MyBatis 中有两种类型的事务管理器(也就是 type="[JDBC|MANAGED]"):
-
JDBC – 这个配置直接使用了 JDBC 的提交和回滚设施,它依赖从数据源获得的连接来管理事务作用域。
-
MANAGED – 这个配置几乎没做什么。它从不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文)。
数据源(dataSource)
dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源。
- 大多数 MyBatis 应用程序会按示例中的例子来配置数据源。虽然数据源配置是可选的,但如果要启用延迟加载特性,就必须配置数据源。
有三种内建的数据源类型(也就是 type="[UNPOOLED|POOLED|JNDI]"):
UNPOOLED– 这个数据源的实现会每次请求时打开和关闭连接。虽然有点慢,但对那些数据库连接可用性要求不高的简单应用程序来说,是一个很好的选择。 性能表现则依赖于使用的数据库,对某些数据库来说,使用连接池并不重要,这个配置就很适合这种情形。UNPOOLED 类型的数据源仅仅需要配置以下 5 种属性:
driver
– 这是 JDBC 驱动的 Java 类全限定名(并不是 JDBC 驱动中可能包含的数据源类)。url
– 这是数据库的 JDBC URL 地址。username
– 登录数据库的用户名。password
– 登录数据库的密码。defaultTransactionIsolationLevel
– 默认的连接事务隔离级别。defaultNetworkTimeout
– 等待数据库操作完成的默认网络超时时间(单位:毫秒)。查看java.sql.Connection#setNetworkTimeout()
的 API 文档以获取更多信息。
作为可选项,你也可以传递属性给数据库驱动。只需在属性名加上“driver.”前缀即可,例如:
driver.encoding=UTF8
这将通过 DriverManager.getConnection(url, driverProperties) 方法传递值为 UTF8
的 encoding
属性给数据库驱动。
POOLED– 这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来,避免了创建新的连接实例时所必需的初始化和认证时间。 这种处理方式很流行,能使并发 Web 应用快速响应请求。
除了上述提到 UNPOOLED 下的属性外,还有更多属性用来配置 POOLED 的数据源:
poolMaximumActiveConnections
– 在任意时间可存在的活动(正在使用)连接数量,默认值:10poolMaximumIdleConnections
– 任意时间可能存在的空闲连接数。poolMaximumCheckoutTime
– 在被强制返回之前,池中连接被检出(checked out)时间,默认值:20000 毫秒(即 20 秒)poolTimeToWait
– 这是一个底层设置,如果获取连接花费了相当长的时间,连接池会打印状态日志并重新尝试获取一个连接(避免在误配置的情况下一直失败且不打印日志),默认值:20000 毫秒(即 20 秒)。poolMaximumLocalBadConnectionTolerance
– 这是一个关于坏连接容忍度的底层设置, 作用于每一个尝试从缓存池获取连接的线程。 如果这个线程获取到的是一个坏的连接,那么这个数据源允许这个线程尝试重新获取一个新的连接,但是这个重新尝试的次数不应该超过poolMaximumIdleConnections
与poolMaximumLocalBadConnectionTolerance
之和。 默认值:3(新增于 3.4.5)poolPingQuery
– 发送到数据库的侦测查询,用来检验连接是否正常工作并准备接受请求。默认是“NO PING QUERY SET”,这会导致多数数据库驱动出错时返回恰当的错误消息。poolPingEnabled
– 是否启用侦测查询。若开启,需要设置poolPingQuery
属性为一个可执行的 SQL 语句(最好是一个速度非常快的 SQL 语句),默认值:false。poolPingConnectionsNotUsedFor
– 配置 poolPingQuery 的频率。可以被设置为和数据库连接超时时间一样,来避免不必要的侦测,默认值:0(即所有连接每一时刻都被侦测 — 当然仅当 poolPingEnabled 为 true 时适用)。
映射器(mappers)
告诉mybatis 映射文件的存放路径
<!-- 使用相对于类路径的资源引用 -->
<mappers>
<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
<mapper resource="org/mybatis/builder/BlogMapper.xml"/>
<mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>
<!-- 使用完全限定资源定位符(URL) -->
<mappers>
<mapper url="file:///var/mappers/AuthorMapper.xml"/>
<mapper url="file:///var/mappers/BlogMapper.xml"/>
<mapper url="file:///var/mappers/PostMapper.xml"/>
</mappers>
<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers>
<!-- <mapper resource="cn/lanqiao/dao/StudentMapper.xml"/>-->
<!-- 此时要求接口的权限定名必须和映射文件的权限定名是完全一致的-->
<mapper class="cn.lanqiao.dao.StudentMapper"></mapper>
</mappers>
<mappers>
<!-- <mapper resource="cn/lanqiao/dao/StudentMapper.xml"/>-->
<!-- 此时要求接口的权限定名必须和映射文件的权限定名是完全一致的-->
<!-- <mapper class="cn.lanqiao.dao.StudentMapper"></mapper>-->
<!-- 将该包下的所有的 接口 的全限定名 注册为映射器 将来在创建映射器的时候 映射文件的名称和路径必须和接口的全限定名保持完全一致-->
<package name="cn.lanqiao.dao"/>
</mappers>
5.MyBatis相应API
5.1 SqlSession工厂构建器SqlSessionFactoryBuilder
常用API:SqlSessionFactory build(InputStream inputStream)
通过加载mybatis的核心文件的输入流的形式构建一个SqlSessionFactory对象
String resource = “org/mybatis/builder/mybatis-config.xml”; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(inputStream);
其中, Resources 工具类,这个类在 org.apache.ibatis.io 包中。Resources 类帮助你从类路径下、文件系统或一个 web URL 中加载资源文件。
5.2 SqlSession工厂对象SqlSessionFactory
SqlSessionFactory 有多个个方法创建SqlSession 实例。常用的有如下两个:
方法 | 解释 |
---|---|
openSession() | 会默认开启一个事务,但事务不会自动提交,也就意味着需要手动提交该事务,更新操作数据才会持久化到数据库中 |
openSession(boolean autoCommit) | 参数为是否自动提交,如果设置为true,那么不需要手动提交事务 |
5.3 SqlSession会话对象
SqlSession 实例在 MyBatis 中是非常强大的一个类。在这里你会看到所有执行语句、提交或回滚事务和获取映射器实例的方法。
执行语句的方法主要有:
<T> T selectOne(String statement, Object parameter)
<E> List<E> selectList(String statement, Object parameter)
int insert(String statement, Object parameter)
int update(String statement, Object parameter)
int delete(String statement, Object parameter)
操作事务的方法主要有:
void commit()
void rollback()
6.代理开发方式
6.1. 代理开发方式介绍
采用 Mybatis 的代理开发方式实现 DAO 层的开发,这种方式是我们后面进入企业的主流。
Mapper 接口开发方法只需要程序员编写Mapper 接口(相当于Dao 接口),由Mybatis 框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。
Mapper 接口开发需要遵循以下规范:
- Mapper.xml文件中的namespace与mapper接口的全限定名相同
- Mapper接口方法名和Mapper.xml中定义的每个statement的id相同
- Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql的parameterType的类型相同
- Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同
编写UserMapper接口
代理方式实现dao接口 也是myabtis推荐和企业使用的方式
7.MyBatis映射文件深入
SQL 映射文件只有很少的几个顶级元素(按照应被定义的顺序列出):
cache
– 该命名空间的缓存配置。cache-ref
– 引用其它命名空间的缓存配置。resultMap
– 描述如何从数据库结果集中加载对象,是最复杂也是最强大的元素。parameterMap
– 老式风格的参数映射。此元素已被废弃,并可能在将来被移除!请使用行内参数映射。文档中不会介绍此元素。sql
– 可被其它语句引用的可重用语句块。insert
– 映射插入语句。update
– 映射更新语句。delete
– 映射删除语句。select
– 映射查询语句。
7.1.动态 SQL 之
我们根据实体类的不同取值,使用不同的 SQL语句来进行查询。比如在 id如果不为空时可以根据id查询,如果username 不同空时还要加入用户名作为条件。这种情况在我们的多条件组合查询中经常会碰到。
<select id="selectStuByCondition" resultType="Stu">
select * from emp where 1=1
<if test="empno != null">
and empno =#{empno}
</if>
<if test="ename!=null">
and ename like concat('%',#{ename},'%');
</if>
</select>
@Test
public void selectConditionTest(){
Stu stu = new Stu();
stu.setEmpno(1015);
// stu.setEname("Lucy");
List<Stu> list = mapper.selectStuByCondition(stu);
System.out.println(list);
}
@Test
public void selectConditionTest(){
Stu stu = new Stu();
// stu.setEmpno(1015);
stu.setEname("张");
List<Stu> list = mapper.selectStuByCondition(stu);
System.out.println(list);
}
@Test
public void selectConditionTest(){
Stu stu = new Stu();
stu.setEmpno(1007);
stu.setEname("张");
List<Stu> list = mapper.selectStuByCondition(stu);
System.out.println(list);
}
7.2.动态标签之Where
7.3.foreach
动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)。比如:
<select id="selectStuIn" resultType="Stu" >
select * from emp where empno in
/*
collection指定集合的类型 collection list
separator 遍历之后 元素之间的分隔符
open 以什么开始
close 以什么结束
item 遍历的集合对象
*/
<foreach collection="list" separator="," open="(" close=")" item="empnos">
#{empnos}
</foreach>
</select>
7.4.choose、when、otherwise
有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。
还是上面的例子,但是策略变为:传入了 “title” 就按 “title” 查找,传入了 “author” 就按 “author” 查找的情形。若两者都没有传入,就返回标记为 featured 的 BLOG(这可能是管理员认为,与其返回大量的无意义随机 Blog,还不如返回一些由管理员精选的 Blog)。
<select id="selectStuByCondition2" resultType="Stu">
select * from emp
<where>
<choose>
<when test="empno!=null">
and empno=#{empno}
</when>
<when test="ename!=null">
and ename like concat('%',#{ename},'%')
</when>
<otherwise>
and sal < 2000
</otherwise>
</choose>
</where>
</select>
在多个条件下 只能同时根据一个条件查询 ‘
@Test
public void selectCondition2Test(){
Stu stu = new Stu();
stu.setEmpno(1005);
stu.setEname("张");
List<Stu> list = mapper.selectStuByCondition2(stu);
System.out.println(list);
}
7.5.sql
将重复的sql单独提炼出来 在需要的 地方使用include 包含即可
MyBatis映射文件配置:
-
:插入
-
:修改
-
:删除
-
:where条件
-
:if判断
-
:循环
-
:sql片段抽取
8. 数据类型的映射
8.1.typeHandlers标签
无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时, 都会用类型处理器将获取的值以合适的方式转换成 Java 类型。下表描述了一些默认的类型处理器(截取部分)。
你可以重写类型处理器或创建你自己的类型处理器来处理不支持的或非标准的类型。具体做法为:实现 org.apache.ibatis.type.TypeHandler 接口, 或继承一个很便利的类 org.apache.ibatis.type.BaseTypeHandler, 然后可以选择性地将它映射到一个JDBC类型。例如**需求:**一个Java中的Date数据类型,我想将之存到数据库的时候存成一个1970年至今的毫秒数,取出来时转换成java的Date,即java的Date与数据库的varchar毫秒值之间转换。
/**
* @author Mr.Hu
* @create 2021/04/20
*/
public class DateHandler extends BaseTypeHandler<Date> {
// 将获取到的参数保存到数据库
@Override
public void setNonNullParameter(PreparedStatement ps, int i, Date parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i,parameter.getTime()+"");
}
@Override
public Date getNullableResult(ResultSet rs, String columnName) throws SQLException {
return new Date(Long.valueOf(rs.getString(columnName))) ;
}
@Override
public Date getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return new Date(Long.valueOf(rs.getString(columnIndex))) ;
}
@Override
public Date getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return new Date(Long.valueOf(cs.getString(columnIndex))) ;
}
}
配置处理
public void insertTest(){
Stu stu = new Stu();
stu.setEname("李四");
stu.setJob("mybatis");
stu.setSal(new BigDecimal(1500.00));
stu.setHiredate(new Date());
mapper.insertStu(stu);//新增
sqlSession.commit();//手动提交事务
}
@Test
public void selectOneTest(){
Stu stu = mapper.selectStuById(1017);
System.out.println(stu);
}
9. 当列名和属性名不一致的时候的处理
方式一:在sql语句中 使用别名
<sql id="base">
select empno no,ename name,hiredate ,sal from emp
</sql>
方式二 可以使用结果映射
在数据库中 往往还有 在字段命名中 多个单词之间使用_链接的情况。在Java的属性中 我们都会祛除下划线 然后从第二个单词开始 每个单词的首字母小写 我们也将这种命名方式称为驼峰命名法 在mybatis中对于这种情况的处理 可以很简单 给mybatis增加一个配置 就可以自动帮助我们完成由下划线分隔转换为驼峰命名