1.Mybatis核心对象
mybatis:https://mybatis.org/mybatis-3/zh/index.html
主要有三个核心对象:SqlSessionFactoryBuilder, SqlSessionFactory, SqlSession
1.1 SqlSessionFactoryBuilder
1.1.1 介绍
这个是一个构建器,是用来构建SqlSessionFactory对象的,SqlSessionFactoryBuilder可以通过读取mybatis的配置文件,然后构建一个SqlSessionFactory对象,SqlSessionFactoryBuilder将mybatis配置文件、xml映射文件和Mapper 接口的映射关系解析好,然后放在java对象中,java对象存在于内存中,内存中访问会非常快的,那么我们每次去用的时候就不需要重新去解析xml了,SqlSessionFactoryBuilder解析配置之后,生成的对象就是SqlSessionFactory,这个是一个重量级的对象,创建他是比较耗时的,所以一般一个db我们会创建一个SqlSessionFactory对象,然后在系统运行过程中会一直存在,而SqlSessionFactoryBuilder用完了就可以释放了。
1.1.2 作用域
这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。 因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。
1.1.3 API
alt +7 左侧的Structrue
查找接⼝的实现类:Ctrl + H
三种方式:Reader, InputStream, Confiugration也就是字符流,字节流和类的方式
1.2 SqlSessionFactory
1.2.1 介绍
SqlSessionFactory是一个工厂,是用来创建SqlSession的工厂,SqlSessionFactory是一个重量级的对象,一般一个db对应一个SqlSessionFactory对象,系统运行过程中会一直存在。
SqlSessionFactory是一个接口,这个接口有2个实现DefaultSqlSessionFactory和SqlSessionManager,一般都是通过SqlSessionFactoryBuilder来创建SqlSessionFactory对象。
通过SqlSessionFactoryBuilder来创建SqlSessionFactory对象主要有2种方式,一种通过读取mybatis配置文件的方式,另外一种是硬编码的方式,springboot中会使用到硬编码的方式。
1.2.2 作用域
SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。 使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次。因此 SqlSessionFactory 的最佳作用域是应用(application)作用域。
有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。
1.2.3 API
openSession()方法的参数为boolean值时,若传入的对象是true标识开启事务控制,自动提交,若传入的值是false标识关闭事务控制。
若不传入参数,默认为false。
1.2.4案例
1.UserMappe.class接口添加以下方法
/**
* 插入用户
*/
public int insertUser(User user);
2.UserMappe.xml文件添加以下内容
<!--public int insertUser(User user);-->
<insert id="insertUser" parameterType="user">
insert into users values(null, #{uname}, #{uage})
</insert>
3.TestMybatis测试类添加以下测试方法
@Test
public void testInserUser() throws IOException {
///1.获取核心配置类
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
//2.创建SqlSessionFacotry
SqlSessionFactory sqlSessionFacotry = new SqlSessionFactoryBuilder().build(is);
//3.获取SqLSession对象
SqlSession session = sqlSessionFacotry.openSession();
/**
* 1.方法 mapper运行完毕使用session.commit()方法提交事务-96行
* 2.使用openSession(true)自动提交事务
*/
//4.执行sql语句
UserMapper mapper = session.getMapper(UserMapper.class);
User user = new User();
user.setUname("lily");
user.setUage(23);
mapper.insertUser(user);
// session.commit();
//5。释放资源
session.close();
}
1.3 SqlSession
1.3.1 介绍
SqlSession就类似于jdbc中Connection连接对象,在mybatis中叫做Sql会话对象,一般一个db操作使用一个SqlSession对象,所以这个对象一般是方法级别的,方法结束之后,这个对象就销毁了,这个对象可以调用sqlSessionFactory.openSession的方法来进行获取。
我们可以直接通过SqlSession对象来调用mapper xml中各种db操作,需要指定具体的操作的id,id的格式为namespace.操作的id。
1.3.2 作用域
每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求(request)或方法作用域。
1.3.3 api
每次收到 HTTP 请求,就可以打开一个 SqlSession,返回一个响应后,就关闭它。 这个关闭操作很重要,为了确保每次都能执行关闭操作,你应该把这个关闭操作放到 finally 块中。
try(){
}finally{
sqlSession.close();
}
例如,在开发中常常使用一个工具类提供sqlSession的获取和关闭:
package com.example.utils;
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;
/**
* ClassName: MyBatisUtil
* Package: com.example.utils
* Description:
*
* @Create 2023/3/28 12:19
* @Version 1.0
*/
public class MyBatisUtil
{
//利用static(静态)属于类不属于对象,且全局唯一
private static SqlSessionFactory sqlSessionFactory = null;
//利用静态块在初始化类时实例化sqlSessionFactory
static {
InputStream is= null;
try {
is = Resources.getResourceAsStream("mybatis-config.xml");
sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
} catch (IOException e) {
e.printStackTrace();
throw new ExceptionInInitializerError(e);
}
}
/**
* openSession 创建一个新的SqlSession对象
* @return SqlSession对象
*/
public static SqlSession openSession(boolean autoCommit){
return sqlSessionFactory.openSession();
}
/**
* 释放一个有效的SqlSession对象
* @param session 准备释放SqlSession对象
*/
public static void closeSession(SqlSession session){
if(session != null){
session.close();
}
}
}
1.3.4 mapper接口
可以通过SqlSession直接调用mapper.xml中的db操作,不过更简单的以及推荐的方式是使用Mapper接口,Mapper接口中的方法和mapper xml文件中的各种db操作建立了映射关系,是通过Mapper接口完整名称+方法名称和mapper xml中的namespace+具体操作的id来进行关联的,然后我们直接调用Mapper接口中的方法就可以间接的操作db了,使用想当方便,Mapper接口需要通过SqlSession获取,传入Mapper接口对应的Class对象,然后会返回这个接口的实例,如:
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
2 MyBatis核心配置文件
核心配置文件主要用于配置连接数据库的环境以及MyBatis的全局配置信息,MyBatis的核心配置文件名称可以随便起名,建议使用mybatis-config.xml
2.1 mybatis-config.xml头部约束
1.dtd约束
xml文件的声明处引入dtd约束文件 ===》 规定xml中语法规则。(会自动提示)
<?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">
2.引入约束:
File—>Settings—>Languages & Frameworks—>Schemas and DTDs—>点击+号—>把复制的dtd约束黏贴—>OK
3.导入本地约束文件
2.2 mybatis-config.xml配置文件的元素
mybatis-config.xml 文件中的元素节点是有一定顺序的,节点位置必须按以上位置排序,否则会编译错误。
The content of element type "configuration" must match "
(properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objectWrapperFactory?,
reflectorFactory?,plugins?,environments?,databaseIdProvider?,mappers?)".
2.2.1 属性properties标签
属性可以在外部进行配置,并可以进行动态替换。
1.属性文件中配置,如db.properties或jdbc.properties
内容如下:
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&characterEncoding=utf8&useUnicode=true&useSSL=false
jdbc.username=root
jdbc.password=root
设置好的属性在核心配置文件mybatis-config.xml中使用方式如下:
<properties resource="db.properties"></properties>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
2.Property元素的子元素中设置,也可以同时动态替换
<properties resource="db.properties">
<property name="username" value="root"/>
<property name="password" value="root"/>
</properties>
3.通过build()方法
1.UserMapper.class
/**
* 查询所有用户
*/
public List<User> findAll();
2.UserMapper.xml
<!--public List<User> findAll();-->
<select id="findAll" resultType="user">
select * from users
</select>
3.TestMybatis.java
@Test
public void testFindAll() throws IOException {
///1.获取核心配置类
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
Properties properties = new Properties();
properties.setProperty("jdbc.driver","com.mysql.cj.jdbc.Driver");
properties.setProperty("jdbc.url","jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&characterEncoding=utf8&useUnicode=true&useSSL=false");
properties.setProperty("jdbc.username","root");
properties.setProperty("jdbc.password","root");
//2.创建SqlSessionFacotry
SqlSessionFactory sqlSessionFacotry = new SqlSessionFactoryBuilder().build(is, properties);
//3.获取SqLSession对象
SqlSession session = sqlSessionFacotry.openSession();
//4.执行sql语句
UserMapper mapper = session.getMapper(UserMapper.class);
List<User> userList = mapper.findAll();
System.out.println("userList = " + userList);
//5。释放资源
session.close();
}
4总结
properties配置有三种方式,resource或者url指定,直接配置在子节点properties中,另一种就是上一篇提到的,直接代码中去其他地方读取properties文件,然后传入build方法。
那么这三种方式既然都能配置,假如属性配置重复了,优先级是怎么样的呢?
properties优先级
properties配置的属性如果重复,优先级如下:
1、第一优先:在代码中直接通过properties传入build方法。
2、第二优先:通过resource或者url读取到的properties文件中属性。
3、第三优先:直接在properties内的子标签property内定义的属性。
在实际开发中,建议是只使用一种,使用多种方式混合的话会给后期维护造成困难,而且不同类型的配置属性混合时可读性也不好。
2.2.2 设置settings运行时配置
是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。 下表描述了设置中各项设置的含义、默认值等。
设置(settings)
设置名 | 描述 | 有效值 | 默认值 |
---|---|---|---|
mapUnderscoreToCamelCase | 是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。 | true 或 false | False |
lazyLoadingEnabled | 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态 | true 或 false | false |
案例-驼峰式命名 |
1 准备数据库
create table t_users(
user_id int primary key auto_increment,
user_name varchar(20) not null,
user_age int not null
);
insert into t_users(user_id,user_name,user_age) values(null,'张三',20),(null,'李四',18);
2 实体类文件Users
package com.example.pojo;
/**
* ClassName: Users
* Package: com.example.pojo
* Description:
*
* @Create 2023/3/16 15:11
* @Version 1.0
*/
public class Users {
private int userId;
private String userName;
private String userAge;
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserAge() {
return userAge;
}
public void setUserAge(String userAge) {
this.userAge = userAge;
}
@Override
public String toString() {
return "Users{" +
"userId=" + userId +
", userName='" + userName + '\'' +
", userAge='" + userAge + '\'' +
'}';
}
}
3 mybatis-config.xml核心配置文件不用修改
<?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>
<!--引入properties文件-->
<properties resource="db.properties">
<property name="jdbc.username" value="root"/>
<property name="jdbc.password" value="root"/>
</properties>
<!--将下划线映射为驼峰-->
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<!--设置类型别名-->
<typeAliases>
<!--
以包为单位,将包下所有的类型设置设置默认的类型别名,即类名且不区分大小写
-->
<package name="com.example.pojo"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<!-- 引入映射文件 -->
<mappers>
<!--
以包为单位引入映射文件
要求:
1. mapper接口所在的包要和映射文件所在的包一致
2. mapper接口要和映射文件的名字一致
-->
<package name="com.example.mapper"/>
</mappers>
</configuration>
4 UsersMapper.class接口
package com.example.mapper;
/**
* ClassName: UsersMapper
* Package: com.example.mapper
* Description:
*
* @Create 2023/3/16 15:29
* @Version 1.0
*/
public interface UsersMapper {
}
5 UsersMapper.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.example.mapper.UsersMapper">
<!-- namespace要和mapper接口的全类名保持一致 -->
<!-- sql语句要和接口的方法名保持一致 -->
</mapper>
6 测试类com.example.test.TestUsers
7 根据Id查询Users
7.1 UsersMapper.class接口添加方法
public interface UsersMapper {
/**
* 根据id查询Users
*/
public List<Users> findAll();
}
7.2 UsersMapper.xml映射文件添加select语句
<?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.example.mapper.UsersMapper">
<!-- namespace要和mapper接口的全类名保持一致 -->
<!-- sql语句要和接口的方法名保持一致 -->
<!--public List<Users> findAll();-->
<select id="findAll" resultType="users">
select * from t_users
</select>
</mapper>
7.3 com.example.test.TestUsers添加测试方法
@Test
public void testFindAll() throws IOException {
//1.获取核心配置类
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
//2.创建SqlSessionFacotry
SqlSessionFactory sqlSessionFacotry = new SqlSessionFactoryBuilder().build(is);
//3.获取SqLSession对象
SqlSession session = sqlSessionFacotry.openSession();
//4.执行sql语句
UsersMapper mapper = session.getMapper(UsersMapper.class);
List<Users> usersList = mapper.findAll();
System.out.println("usersList = " + usersList);
//5。释放资源
session.close();
}
7.4 输出结果
DEBUG 03-16 15:41:16,504 ==> Preparing: select * from t_users (BaseJdbcLogger.java:159)
DEBUG 03-16 15:41:16,636 ==> Parameters: (BaseJdbcLogger.java:159)
DEBUG 03-16 15:41:16,714 <== Total: 2 (BaseJdbcLogger.java:159)
usersList = [Users{userId=1, userName='张三', userAge='20'}, Users{userId=2, userName='李四', userAge='18'}]
7.5 验证结果
去掉mybatis-config.xml中的以下语句
<!--将下划线映射为驼峰-->
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
结果如下:
DEBUG 03-16 15:44:26,597 ==> Preparing: select * from t_users (BaseJdbcLogger.java:159)
DEBUG 03-16 15:44:26,684 ==> Parameters: (BaseJdbcLogger.java:159)
DEBUG 03-16 15:44:26,769 <== Total: 2 (BaseJdbcLogger.java:159)
usersList = [null, null]
7.6 除了驼峰式命名外还可以使用自定义映射resultMap
若字段名和实体类中的属性名不一致,则可以通过resultMap设置自定义映射【稍后讲解】
2.2.3 类型别名(typeAliases)
类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。例如:
2.2.3.1 类型别名typeAlias
<!--设置类型别名-->
<typeAliases>
<typeAlias type="com.example.pojo.User" alias="user"></typeAlias>
<typeAlias type="com.example.pojo.Users" alias="users"></typeAlias>
</typeAliases>
这样在使用com.example.pojo.User的时候可以使用user或User
2.2.3.2 类型别名package
<typeAliases>
<package name="com.example.pojo"/>
</typeAliases>
指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母大小写的非限定类名来作为它的别名。
2.2.3.3 @Alias注解方式
@Alias使用的时候也是不区分大小写的
类型别名需要设置package
<typeAliases>
<package name="com.example.pojo"/>
</typeAliases>
@Alias("test")
public class Users {
private int userId;
private String userName;
private String userAge;
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserAge() {
return userAge;
}
public void setUserAge(String userAge) {
this.userAge = userAge;
}
@Override
public String toString() {
return "Users{" +
"userId=" + userId +
", userName='" + userName + '\'' +
", userAge='" + userAge + '\'' +
'}';
}
}
2.2.4 类型处理器(typeHandlers)
由于Java 类型和数据库的JDBC 类型不是一一对应的(比如String 与varchar, Date和varchar),所以我们把Java 对象转换为数据库的值,和把数据库的值转换成Java 对象,需要经过一定的转换,这两个方向的转换就要用到TypeHandler。
以前的例子中,没有做任何的配置,为什么实体类对象里面的一个String属性,可以保存成数据库里面的varchar 字段,或者保存成char 字段?因为MyBatis中已经内置了很多的TypeHandler
Ctrl+N按名字搜索类
package org.apache.ibatis.type;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public interface TypeHandler<T> {
void setParameter(PreparedStatement var1, int var2, T var3, JdbcType var4) throws SQLException;
T getResult(ResultSet var1, String var2) throws SQLException;
T getResult(ResultSet var1, int var2) throws SQLException;
T getResult(CallableStatement var1, int var2) throws SQLException;
}
查找接⼝的实现类:Ctrl + H
如果自己自定义类型转换规则,或者处理类型的时候做一些特殊的事情,就需要自己编写TypeHandler的实现类,需要实现TypeHandler的四个抽象方法,这四个抽象方法分为两类:
Java类型->JDBC类型 | setParameter |
---|---|
JDBC类型->Java类型 | getResult |
还有一种方式是集成BaseTypeHandler |
案例:
2.2.5 对象工厂(objectFactory)
每次 MyBatis 创建结果对象的新实例时,它都会使用一个对象工厂(ObjectFactory)实例来完成实例化工作。 默认的对象工厂需要做的仅仅是实例化目标类,要么通过默认无参构造方法,要么通过存在的参数映射来调用带有参数的构造方法。 如果想覆盖对象工厂的默认行为,可以通过创建自己的对象工厂来实现。
MyBatis中ObjectFactory简介
2.2.6 包装器工厂(objectWrapperFactory)
objectWrapperFactory用于对对象进行包装和后处理操作,在mybatis中用于对结果对象的处理。
2.2.7 反射工具箱(reflectorFactory)
ReflectorFactory接口主要实现了对Reflector对象的创建和缓存。
2.2.8 插件(plugins)
MyBatis Plugin是借助动态代理模式来实现的职责链模式
MyBatis Plugin 跟 Servlet Filter、Spring Interceptor 的功能是类似的,都是在不需要修改原有流程代码的情况下,拦截某些方法调用,在拦截的方法调用的前后,执行一些额外的代码逻辑。它们的唯一区别在于拦截的位置是不同的。Servlet Filter 主要拦截 Servlet 请求,Spring Interceptor 主要拦截 Spring 管理的 Bean 方法(比如 Controller 类的方法等),而 MyBatis Plugin 主要拦截的是 MyBatis 在执行 SQL 的过程中涉及的一些方法。
Java 框架 Mybatis 中Plugins(插件)开发指南
2.2.9 环境配置(environments)
MyBatis可以配置多种环境,default指定使用某种环境
<!--
environments:配置连接数据库的环境
属性:
default:设置默认使用的环境id
-->
<environments default="development">
<!--
environment:配置某个具体的环境
属性:
id:表示连接数据库的环境的唯一标识,不能重复
-->
<environment id="development">
<!--
transactionManager:设置事务管理方式
属性:
type="JDBC|MANAGED"
JDBC:表示当前环境中,执行SQL时,使用的是JDBC中原生的事务管理方式,事务的提交和回滚需要手动来处理
MANAGED: 表示被管理,例如Spring
-->
<transactionManager type="JDBC"/>
<!--
dataSource:配置数据源
属性:
type:设置数据源类型
type="POOLED|UNPOOLED|JNDI"
POOLED:表示使用数据库连接池缓存数据库连接
UNPOOLED:表示不使用数据库连接池缓存数据库连接
JNDI:表示使用上下文中的数据源
-->
<dataSource type="POOLED">
<!--设置连接数据库的驱动-->
<property name="driver" value="${jdbc.driver}"/>
<!--设置连接数据库的地址-->
<property name="url" value="${jdbc.url}"/>
<!--设置连接数据库的用户名-->
<property name="username" value="${jdbc.username}"/>
<!--设置连接数据库的密码-->
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
<environment id="test">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
2.2.10 databaseIdProvider(数据库厂商标识)
MyBatis 可以根据不同的数据库厂商执行不同的语句,这种多厂商的支持是基于映射语句中的 databaseId 属性。 MyBatis 会加载带有匹配当前数据库 databaseId 属性和所有不带 databaseId 属性的语句。 如果同时找到带有 databaseId 和不带 databaseId 的相同语句,则后者会被舍弃。 为支持多厂商特性,只要像下面这样在 mybatis-config.xml 文件中加入 databaseIdProvider 即可:
<databaseIdProvider type="DB_VENDOR">
<property name="SQL Server" value="sqlserver"/>
<property name="DB2" value="db2"/>
<property name="mysql" value="mysql"/>
<property name="Oracle" value="oracle" />
</databaseIdProvider>
在mapper.xml文件中,sql标签上加上属性databaseId=“数据库厂商的别名”。例:
<select id="getEmpById" resultType="emp" databaseId="mysql">
select * from tbl_employee where id = #{id}
</select>
MyBatis之databaseIdProvider多数据库支持
2.2.11 映射器(mappers)
既然 MyBatis 的行为已经由上述元素配置完了,我们现在就要来定义 SQL 映射语句了。 但首先,我们需要告诉 MyBatis 到哪里去找到这些语句。 在自动查找资源方面,Java 并没有提供一个很好的解决方案,所以最好的办法是直接告诉 MyBatis 到哪里去找映射文件。 你可以使用相对于类路径的资源引用,或完全限定资源定位符(包括 file:/// 形式的 URL),或类名和包名等。例如:
<!-- 使用相对于类路径的资源引用 -->
<mappers>
<mapper resource="com/example/mapper/UserMapper.xml"/>
</mappers>
<!-- 使用完全限定资源定位符(URL) -->
<mappers>
<mapper url="file:///F:/ideaProject/blog/mybatis/src/main/resources/com/example/mapper/UserMapper.xml"/>
</mappers>
<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers>
<mapper class="com.example.mapper.UserMapper"/>
</mappers>
<!-- 将包内的映射器接口全部注册为映射器 -->
<mappers>
<!--
以包为单位引入映射文件
要求:
1. mapper接口所在的包要和映射文件所在的包一致
2. mapper接口要和映射文件的名字一致
-->
<package name="com.example.mapper"/>
</mappers>
3.mybatis映射文件(XML 映射器-xxxMapper.xml)
3.1 头部约束
<?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">
3.2 映射器
映射器实现了数据库和Java之间数据的交互。映射器包含了增删改查和结果映射。MyBatis的强大之处在于SQL映射文件的编写。
3.2.1 分类
mybatis映射器主要有三种方式:
1.单纯的sqlMapper映射
若要使用sqlMapper映射,必须要引入mybatis-config.xml 全局配置文件,它配置了Mybatis的运行环境,引入sqlMapper文件等。
2.sqlMapper和接口混合映射
若要使用sqlMapper和接口混合映射,有几个必须的前提条件:
(1).sqlMapper文件要和接口在同一个包下
(2).sqlMapper文件名要和接口名一致
(3).接口的方法名要和sqlMapper中的id值一致
(4).sqlMapper中的namespace的值要指向接口路径
(5).接口的入参类型要和sqlMapper中的parameterType类型一致
(6).接口的返回值类型要和sqlMapper中的resultType类型一致
3.注解与接口混合映射
注解与接口混合映射,其实际操作是对接口中的方法进行注解,将sql语句直接放入,与方法进行绑定。
1.@Insert 增
2.@Delete 删
3.@Update 改
4.@Select 查
3.2.2 映射常用元素
3.2.2.1 映射查询-select
select元素用于映射查询语句,从数据库中查询数据并返回。例如:
<!-- sql语句要和接口的方法名保持一致 -->
<select id="findUserById"
parameterType="int"
resultType="User">
select * from users where uid = #{id}
</select>
select元素的id是findUserById,参数类型是int,返回值是:User类(这里应该是User类的 全限定类名,但是由于外面配置了类型别名,所有这里是别名),#{id}代表创建一个预处理语句参数,相当于sql语句中的占位符“?”。select元素还有一些其它的配置属性:
3.2.2.2 映射插入-insert
插入语句,执行返回一个整数,代表插入的条数
<!--public int insertUser(User user);-->
<insert id="insertUser" parameterType="user">
insert into users values(null, #{uname}, #{uage})
</insert>
输出结果
DEBUG 03-17 08:39:21,725 ==> Preparing: insert into users values(null, ?, ?) (BaseJdbcLogger.java:159)
DEBUG 03-17 08:39:21,783 ==> Parameters: lily(String), 23(Integer) (BaseJdbcLogger.java:159)
DEBUG 03-17 08:39:21,790 <== Updates: 1 (BaseJdbcLogger.java:159)
result = 1
user = User{uid=0, uname='lily', uage=23}
使用自增主键获得主键值
<!--public int insertUser(User user);-->
<insert id="insertUser" parameterType="user" keyProperty="uid" useGeneratedKeys="true">
insert into users values(null, #{uname}, #{uage})
</insert>
输出结果
DEBUG 03-17 08:37:12,934 ==> Preparing: insert into users values(null, ?, ?) (BaseJdbcLogger.java:159)
DEBUG 03-17 08:37:12,998 ==> Parameters: lily(String), 23(Integer) (BaseJdbcLogger.java:159)
DEBUG 03-17 08:37:13,005 <== Updates: 1 (BaseJdbcLogger.java:159)
result = 1
user = User{uid=11, uname='lily', uage=23}
不使用自增主键获得主键值
<insert id="insertUser" parameterType="user">
<selectKey keyProperty="uid" resultType="int" order="BEFORE">
select if(max(uid) is null, 1, max(uid) + 1) as newId from users
</selectKey>
insert into users values(null, #{uname}, #{uage})
</insert>
输出结果
DEBUG 03-17 08:43:11,472 ==> Preparing: select if(max(uid) is null, 1, max(uid) + 1) as newId from users (BaseJdbcLogger.java:159)
DEBUG 03-17 08:43:11,532 ==> Parameters: (BaseJdbcLogger.java:159)
DEBUG 03-17 08:43:11,575 <== Total: 1 (BaseJdbcLogger.java:159)
DEBUG 03-17 08:43:11,580 ==> Preparing: insert into users values(null, ?, ?) (BaseJdbcLogger.java:159)
DEBUG 03-17 08:43:11,582 ==> Parameters: lily(String), 23(Integer) (BaseJdbcLogger.java:159)
DEBUG 03-17 08:43:11,588 <== Updates: 1 (BaseJdbcLogger.java:159)
result = 1
user = User{uid=13, uname='lily', uage=23}
3.2.2.3 映射更新-update
/**
* 更新用户
*/
public int updateUser(User user);
<update id="updateUser" parameterType="user">
update users set uname=#{uname} , uage=#{uage} where uid=#{uid}
</update>
@Test
public void testUpdateUser() throws IOException {
///1.获取核心配置类
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
//2.创建SqlSessionFacotry
SqlSessionFactory sqlSessionFacotry = new SqlSessionFactoryBuilder().build(is);
//3.获取SqLSession对象
SqlSession session = sqlSessionFacotry.openSession(true);
//4.执行sql语句
UserMapper mapper = session.getMapper(UserMapper.class);
User user = new User();
user.setUname("lily");
user.setUage(33);
user.setUid(13);
int result = mapper.updateUser(user);
System.out.println("result = " + result);
System.out.println("user = " + user);
// session.commit();
//5。释放资源
session.close();
}
3.2.2.4 映射删除-delete
/**
* 删除用户通过id
*/
public int deleteUserById(int id);
/**
* 删除用户
*/
public int deleteUser(User user);
<!--public int deleteUserById(int id);-->
<delete id="deleteUserById" parameterType="int">
delete from users where uid=#{id}
</delete>
<!--public int deleteUser(User user);-->
<delete id="deleteUser" parameterType="user">
delete from users where uid=#{uid}
</delete>
@Test
public void testDeleteUser() throws IOException {
///1.获取核心配置类
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
//2.创建SqlSessionFacotry
SqlSessionFactory sqlSessionFacotry = new SqlSessionFactoryBuilder().build(is);
//3.获取SqLSession对象
SqlSession session = sqlSessionFacotry.openSession(true);
//4.执行sql语句
UserMapper mapper = session.getMapper(UserMapper.class);
// int result = mapper.deleteUserById(1);
User user = new User();
user.setUid(12);
int result = mapper.deleteUser(user);
System.out.println("result = " + result);
//5。释放资源
session.close();
}
3.2.2.5 sql片段
sql片段,可以记录一段公共sql片段,在使用的地方通过include标签进行引入,以下依findUserById使用sql片段
<select id="findUserById"
parameterType="int"
resultType="User">
select * from users where uid = #{id}
</select>
<sql id="usersColumns">
${alias}.uid, ${alias}.uname, ${alias}.uage
</sql>
<select id="findUserById"
parameterType="int"
resultType="User">
select
<include refid="usersColumns">
<property name="alias" value="users"></property>
</include>
from users where uid = #{id}
</select>
<sql id="columns">
uid, uname, uage
</sql>
<sql id="someinclude">
from ${include_target}
</sql>
<select id="findUserById" parameterType="int" resultType="User">
select
<include refid="columns"></include>
<include refid="someinclude">
<property name="include_target" value="users"/>
</include>
where uid=#{uid}
</select>
3.2.2.6 resultMap
resultMap 是 Mybatis 最强大的元素之一,它可以将查询到的复杂数据(比如查询到几个表中数据)映射到一个结果集当中。常用于多表查询。
resultType 和 resultMap 区别
resultType:直接表示返回类型,包括基础数据类型和复杂数据类型。
resultMap 则是对外部 resultMap 定义的引用,对应外部 resultMap 的 id,表示返回结果映射到哪一个 resultMap 上。它的应用场景一般是:数据库字段信息与对象属性不一致或者需要做复杂的联合查询以便自由控制映射结果。
数据库字段信息与对象属性不一致简单示例
<resultMap id="userMap" type="user">
<id property="uid" column="user_id"></id>
<result property="uname" column="user_name"></result>
<result property="uage" column="user_age"></result>
</resultMap>
<select id="findAll" resultMap="userMap">
select * from t_users
</select>
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/140753.html