目录
Mybatis调用接口Dao的接口方法,创建UserMapper接口
使用JDK的动态代理类Proxy,根据映射接口,创建动态代理对象
What框架? Why框架
1、框架即framework。
其实就是某种应用的半成品,就是一组组件,供你选用完成你自己的系统。
简单理解就是一套资源,包含jar包、源码、帮助文档、示例等。
2、为什么要用框架开发?
使用别人成熟的框架,就相当于让别人帮你完成一些基础工作,你只需要集中精力完成系统的业务逻辑设计。这样可以节省开发时间,提高代码重用性,让开发变得更简单。
Mybatis简介
MyBatis 是支持定制化 SQL以及高级映射(ORM)的优秀的持久层框架。
MyBatis 发展历史
Mybatis的前身是 Apache的一个开源项目 iBatis, 2010年迁移到了google code 改名为 MyBatis,最后又迁移到了Github。
mybatis – MyBatis 3 | 简介http://www.mybatis.org/mybatis-3/zh/index.html
MyBatis的优点
基于SQL语法,简单易学,能了解底层组装过程,SQL语句封装在配置文件中,便于统一管理与维护,降低了程序的耦合度,程序调试方便。
Mybatis配置
引入依赖
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.27</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
mybatis.xml配置文件
mybatis配置顺序如下,不能颠倒,也就是如果有properties属性配置,一定放到最前面,settings放到第二个位置,以此类推
<?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>
<!--日志配置(mybatis执行的日志,主要sql语句和参数),STDOUT_LOGGING配置日志打印控制台-->
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<environments default="dev">
<environment id="dev">
<!--事务管理器JDBC-->
<transactionManager type="JDBC"></transactionManager>
<!--数据源,使用连接池-->
<dataSource type="POOLED">
<!--数据库驱动-->
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<!--连接字符串-->
<!--&表示&,因为&在xml表示其他含义-->
<property name="url"
value="jdbc:mysql://localhost:3306/db1?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai"/>
<!--数据库用户名-->
<property name="username" value="root"/>
<!--数据库密码-->
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!--自定义的映射文件-->
<mappers>
<!--resource 引入的Mapper映射文件的路径,类路径的资源路径-->
<mapper resource="mapper/UserMapper.xml"></mapper>
</mappers>
</configuration>
写跟数据库表对应的java实体类
package com.tjetc.entity;
/**
* 注意点:
* 1、如果要定义有参的构造方法, 原则上一定要定义一个无参的构造方法, 因为mybatis使用反射创建对象, 优先调用无参构造方法
* 如果不定义无参构造方法, mybatis就会反射调用有参构造方法, 有可能造成参数对应错误或者类型对应不上, 会造成错误或出现异常
* 2、实体类至少要有set方法, 这样才能把数据库查询的数据设置到实体类定义的成员变量中
*/
public class User {
private Long id;
private String username;
private String password;
public User(Long id, String username, String password) {
this.id = id;
this.username = username;
this.password = password;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
映射文件UserMapper.xml
映射文件位置为:src/main/resources/mapper/UserMapper.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" >
<!--namespace 命名空间-->
<mapper namespace="test">
<!--增删改查四大标签-->
<!--select 查询标签,id唯一标识标签-->
<!--resultType 表示返回值类型,如果返回值是集合,resultType 表示集合里元素的类型-->
<select id="selectList" resultType="com.tjetc.entity.User">
select * from `user`
</select>
<!--mybatis 的sql语句中传参数使用 #{参数名称}-->
<!--sql中只有一个参数,参数的具体名称没有限定-->
<!--标准写法: parameterType 参数类型, 全限定名 包名+类名
resultType 返回结果类型, 全限定名 包名+类名-->
<select id="selectById" parameterType="java.lang.Long" resultType="com.tjetc.entity.User">
select * from `user` where id=#{id}
</select>
<!-- <update id="">-->
<!-- </update>-->
<!-- <insert id="">-->
<!-- </insert>-->
<!-- <delete id="">-->
<!-- </delete>-->
</mapper>
测试程序
package com.tjetc;
import com.tjetc.common.SqlSessionUtils;
import com.tjetc.entity.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 org.junit.Test;
import java.io.IOException;
import java.util.List;
public class Test1 {
//@Test注解的作用: 执行@Test标记的方法
@Test
public void testSelectList() throws IOException {
//1、获取SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//2、获取SqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = builder.build(Resources.getResourceAsReader("mybatis.xml"));
//3、获取SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
//4、调用SqlSession对象的api方法并获取数据
//Mapper映射文件中配置的namespace的值,目的调用四大标签中的sql语句
List<User> users = sqlSession.selectList("test.selectList");
//5、打印数据
System.out.println(users);
//6、关闭SqlSession
sqlSession.close();
}
@Test
//封装后方法后的调用优化
public void testSelectById() throws IOException {
// //1、获取SqlSessionFactoryBuilder对象
// SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
// //2、获取SqlSessionFactory对象
// SqlSessionFactory sqlSessionFactory = builder.build(Resources.getResourceAsReader("mybatis.xml"));
// //3、获取SqlSession对象
// SqlSession sqlSession = sqlSessionFactory.openSession();
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
//4、调用SqlSession的方法
User user = sqlSession.selectOne("test.selectById", 4L);
//5、打印
System.out.println(user);
//6、关闭资源
SqlSessionUtils.close(sqlSession);
}
}
封装在common下的SqlSessionUtils类
package com.tjetc.common;
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;
//工具类
public class SqlSessionUtils {
//1、获取SqlSessionFactoryBuilder对象
static SqlSessionFactoryBuilder builder;
//2、获取SqlSessionFactory对象
static SqlSessionFactory sqlSessionFactory = null;
static {
builder = new SqlSessionFactoryBuilder();
try {
sqlSessionFactory = builder.build(Resources.getResourceAsReader("mybatis.xml"));
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 获取SqlSession
*
* @return
*/
public static SqlSession getSqlSession() {
//3、获取SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
return sqlSession;
}
/**
* 关闭资源
*
* @param sqlSession
*/
public static void close(SqlSession sqlSession) {
sqlSession.close();
}
}
使用别名
在mybatis.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>
<settings>
<!--日志配置(mybatis执行的日志,主要sql语句和参数),STDOUT_LOGGING配置日志打印控制台-->
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<!--配置别名-->
<typeAliases>
<!--配置User的别名:不区分大小写-->
<typeAlias type="com.tjetc.entity.User" alias="User"/>
</typeAliases>
<environments default="dev">
<environment id="dev">
<!--事务管理器JDBC-->
<transactionManager type="JDBC"></transactionManager>
<!--数据源,使用连接池-->
<dataSource type="POOLED">
<!--数据库驱动-->
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<!--连接字符串-->
<!--&表示&,因为&在xml表示其他含义-->
<property name="url"
value="jdbc:mysql://localhost:3306/db1?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai"/>
<!--数据库用户名-->
<property name="username" value="root"/>
<!--数据库密码-->
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!--自定义的映射文件-->
<mappers>
<!--resource 引入的Mapper映射文件的路径,类路径的资源路径-->
<mapper resource="mapper/UserMapper.xml"></mapper>
<mapper resource="mapper/UserMapper1.xml"></mapper>
</mappers>
</configuration>
Mybatis调用接口Dao的接口方法,创建UserMapper接口
package com.tjetc.dao;
import com.tjetc.entity.User;
import java.util.List;
/**
* 定义mapper接口
*/
public interface UserMapper {
List<User> selectList();
User selectById(Long id);
}
修改UserMapper.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" >
<!--namespace 命名空间-->
<!--如果使用接口, namespace的值为接口的全限定名: 包名+类名 -->
<mapper namespace="com.tjetc.dao.UserMapper">
<!--mapper映射文件中,都可以使用别名-->
<select id="selectList" resultType="user">
select * from `user`
</select>名+类名-->
<!--<select id="selectById" parameterType="java.lang.Long" resultType="com.tjetc.entity.User">-->
<!--使用别名:parameterType resultType不区分大小写-->
<select id="selectById" parameterType="Long" resultType="User">
select * from `user` where id=#{id}
</select>
</mapper>
测试:
package com.tjetc;
import com.tjetc.dao.UserMapper;
import com.tjetc.common.SqlSessionUtils;
import com.tjetc.entity.User;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
public class Test2 {
@Test
public void testUserMapper() {
//获取SqlSession对象
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
//获取mapper接口对应的代理类对象(技术:jdk动态代理)
//mapper是代理对象, 通过接口的全限定名 找到mapper映射文件, 在通过接口方法名称找到mapper映射文件 找到对应的四大标签,
//使用jdbc技术, 把标签中的sql语句发送数据库执行, 接收返回值。
// 因此, 我们只需要定义mapper接口不需要定义mapper接口对应的实现类
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//调用mapper的方法
List<User> users = mapper.selectList();
System.out.println(users);
User user = mapper.selectById(3L);
System.out.println(user);
}
}
mybatis.xml配置详细说明
properties配置
resources目录下创建db.properties
driverName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/db1?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
username=root
password=123456
修改mybatis.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"></properties>
<settings>
<!--日志配置(mybatis执行的日志,主要sql语句和参数),STDOUT_LOGGING配置日志打印控制台-->
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<!--配置别名-->
<typeAliases>
<!--配置User的别名:不区分大小写-->
<typeAlias type="com.tjetc.entity.User" alias="User"/>
</typeAliases>
<environments default="dev">
<environment id="dev">
<!--事务管理器JDBC-->
<transactionManager type="JDBC"></transactionManager>
<!--数据源,使用连接池-->
<dataSource type="POOLED">
<!--${key} 根据key值读取properties配置的value值-->
<!--数据库驱动-->
<property name="driver" value="${driverName}"/>
<!--连接字符串-->
<!--&表示&,因为&在xml表示其他含义-->
<property name="url" value="${url}"/>
<!--数据库用户名-->
<property name="username" value="${username}"/>
<!--数据库密码-->
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<!--自定义的映射文件-->
<mappers>
<!--resource 引入的Mapper映射文件的路径,类路径的资源路径-->
<mapper resource="mapper/UserMapper.xml"></mapper>
<mapper resource="mapper/UserMapper1.xml"></mapper>
</mappers>
</configuration>
typeAliases配置
类型别名是java类型的简写。它仅在XML配置文件中,用于简化合格的class名字
也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean
<?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"></properties>
<settings>
<!--日志配置(mybatis执行的日志,主要sql语句和参数),STDOUT_LOGGING配置日志打印控制台-->
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<!--配置别名-->
<typeAliases>
<!--配置User的别名:不区分大小写-->
<!--<typeAlias type="com.tjetc.entity.User" alias="User"/>-->
<!--package 配置指定包下的所有类, 都可以使用别名, 类名称, 例如:User、Student-->
<package name="com.tjetc.entity"/>
</typeAliases>
<environments default="dev">
<environment id="dev">
<!--事务管理器JDBC-->
<transactionManager type="JDBC"></transactionManager>
<!--数据源,使用连接池-->
<dataSource type="POOLED">
<!--${key} 根据key值读取properties配置的value值-->
<!--数据库驱动-->
<property name="driver" value="${driverName}"/>
<!--连接字符串-->
<!--&表示&,因为&在xml表示其他含义-->
<property name="url" value="${url}"/>
<!--数据库用户名-->
<property name="username" value="${username}"/>
<!--数据库密码-->
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<!--自定义的映射文件-->
<mappers>
<!--resource 引入的Mapper映射文件的路径,类路径的资源路径-->
<mapper resource="mapper/UserMapper.xml"></mapper>
<mapper resource="mapper/UserMapper1.xml"></mapper>
</mappers>
</configuration>
每一个在包 com.tjetc.entity
中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。 比如 com.tjetc.entit.User
的别名为 user
;若有注解,则别名为其注解值 ,例如
//@Alias("user1111") 注解也可以使用配置别名, 并且优先起作用
public class User {
……
}
下面是一些为常见的 Java 类型内建的类型别名。它们都是不区分大小写的,注意,为了应对原始类型的命名重复,采取了特殊的命名风格
别名 | 映射的类型 |
---|---|
_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 |
typeHandlers
无论是mybatis设置一个参数给PreparedStatement,还是从PreparedStatement中返回ResultSet,都要面临一个问题:Java类型与JDBC类型之间的转换。
Java类型面向的是内存,JDBC类型面向的是各种关系型数据库,因此两者有很大的不同。
数据类型映射,是ORM框架中最关键的问题。
自定义类型映射器
你可以重写类型映射器,也可以创建自己的非标准类型映射器。
需要实现org.apache.ibatis.type.TypeHandler接口,或继承类org.apache.ibatis.type.BaseTypeHandler
<!-- mybatis-config.xml -->
<typeHandlers>
<typeHandler handler="org.mybatis.example.ExampleTypeHandler"/>
</typeHandlers>
objectFactory配置
当mybatis每次创建一个新的结果集对象时,都需要使用objectFactory实例。
如果希望重写默认ObjectFactory的行为,可以自定义对象工厂
environments配置
1、mybatis允许你同时配置多个environments。如开发、测试、生产,可以同时配置三个环境。还可以同时对多个不同类型的数据库操作。
注意:虽然你可以同时配置多个环境,但是对于一个SqlSessionFactory实例,只能选择一个环境使用。因此,如果你想同时连接两个数据库,必须要创建两个SqlSessionFactory。
2、transactionManager配置
这里有两种事务管理类型可选,type=[JDBC | MANAGED]
JDBC:依赖于从dataSource返回的Connection对象,直接使用JDBC管理事务
MANAGED:由JavaEE容器管理整个事务
注意:如果使用Spring整合mybatis,无需配置TransactionManager,因为Spring会用自己的事务环境重写mybatis的配置
3、dataSource配置
使用标准数据源接口javax.sql.DataSource配置数据库的JDBC连接
这里有三种数据源类型可选:type="[UNPOOLED | POOLED | JNDI]")
-
UNPOOLED数据源
这个数据源的实现会每次请求时打开和关闭连接。虽然有点慢,但对那些数据库连接可用性要求不高的简单应用程序来说,是一个很好的选择。 性能表现则依赖于使用的数据库,对某些数据库来说,使用连接池并不重要,这个配置就很适合这种情形
-
POOLED
采用数据库连接池配置,可以优化性能,是当前web项目配置首选。
-
JNDI
这个数据源实现是为了能在如 EJB 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的数据源引用
databaseIdProvider配置
DatabaseIdProvider元素主要是为了支持不同厂商的数据库,即同时支持多个数据库
这个配置非常有用,项目如何同时支持多种数据库?
传统做法是生成多套mapper文件,在mybatis.xml中配置使用那套映射文件。这个做法的很大缺陷是:多套映射文件中,会有很多接口的实现是相同的,如果代码修改,需要同时修改多套文件。这给开发额外增加了很大的工作量。
MyBatis 工作原理
1、SqlSession与Connection
DefaultSqlSession是SqlSession接口的实现类
BaseExcecutor中封装了对数据库Connection的管理
数据库的Connection从dataSource中获取,并用Transaction包装
2、SqlSession的getMapper
调用session.getMapper(),输入映射接口,返回接口的实现对象
UserMapper mapper = session.getMapper(UserMapper.class);
调用MapperRegistry的getMapper()方法
断点观察SqlSession-->>configuration -->>mappedStatements(映射文件中的sql读取后,都存于此处)