Mybatis介绍
框架简介:
三层架构:
软件开发常用的架构是三层架构,之所以流行是因为有着清晰的任务划分,一般包括以下三层:
持久层:主要完成与数据库相关的操作,即对数据库的增删改查。
因为数据库访问的对象一般称为Data Access Object(简称DAO),所以有人把持久层叫做DAO层
业务层:主要根据功能需求完成业务逻辑的定义和实现
因为它主要是为上层提供服务的,所以有人把业务层叫做Service层或Business层
表现层:主要完成与最终软件使用用户的交互,需要有交互界面(UI)
因此,有人把表现层称之为web层或View层
三层架构之间调用关系为:表现层调用业务层,业务层调用持久层
各层之间必然要进行数据交互,我们一般使用java实体对象来传递数据
框架:
什么是框架:
框架就是一套规范,既然是规范,你使用这个框架就要遵守这个框架所规定的约束
框架可以理解为半成品软件,框架做好以后,接下来在它基础上进行开发
为什么使用框架:
框架为我们封装好了一些冗余,且重用率低的代码,并且使用反射与动态代理机制,将代码实现了通用性
让开发人员把精力专注在核心的业务代码实现上
比如在使用servlet进行开发时,需要在servlet获取表单的参数,每次都要获取很麻烦
而框架底层就使用反射机制和拦截器机制帮助我们获取表单的值
使用jdbc每次做专一些简单的crud的时候都必须写sql
但使用框架就不需要这么麻烦了,直接调用方法就可以,当然,既然是使用框架,那么还是要遵循其一些规范进行配置
常见的框架:
Java世界中的框架非常的多,每一个框架都是为了解决某一部分或某些问题而存在的
下面列出在目前企业中流行的几种框架(一定要注意他们是用来解决哪一层问题的):
持久层框架:专注于解决数据持久化的框架,常用的有mybatis、hibernate、spring jdbc等等
表现层框架:专注于解决与用户交互的框架,常见的有struts2、spring mvc等等。
全栈框架:能在各层都给出解决方案的框架,比较著名的就是spring,
这么多框架,我们怎么选择呢:
我们以企业中最常用的组合为准来学习Spring + Spring MVC + mybatis(SSM)
Mybatis简介:
原始jdbc操作(查询数据):
对于多次同连接,实际上是对应会话,即与服务连接,并不是占端口,而是服务占对应端口,所以可以有多个相同连接
读取的数据大多数是字符串
原始jdbc操作的分析:
原始jdbc开发存在的问题如下:
数据库连接创建、释放频繁造成系统资源浪费从而影响系统性能
sql 语句在代码中硬编码,造成代码不易维护,实际应用 sql 变化的可能较大,sql 变动需要改变java代码
即又要打包部署,这样非常麻烦
查询操作时,需要手动将结果集中的数据手动封装到实体中
应对上述问题给出的解决方案:
使用数据库连接池初始化连接资源
将sql语句抽取到xml配置文件中
使用反射、内省等底层技术,自动将实体与表进行属性与字段的自动映射
MyBatis是一个优秀的基于ORM的半自动轻量级持久层框架,它对jdbc的操作数据库的过程进行封装
使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动
创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码
mybatis 历史 :
MyBatis 本是apache的一个开源项目iBatis, 2010年6月这个项目由apache software foundation 迁移到了google code
随着开发团队转投到Google Code旗下,iBatis正式改名为MyBatis ,代码于2013年11月迁移到Github
Github地址:https://github.com/mybatis/mybatis-3/
ORM思想:
ORM(Object Relational Mapping)对象关系映射:
O(对象模型):
实体对象,即我们在程序中根据数据库表结构建立的一个个实体javaBean
R(关系型数据库的数据结构):
关系数据库领域的Relational(建立的数据库表)
M(映射):
从R(数据库)到O(对象模型)的映射,可通过XML文件映射
实现:
让实体类和数据库表进行一一对应关系
先让实体类和数据库表对应
再让实体类属性和表里面字段对应
不需要直接操作数据库表,直接操作表对应的实体类对象
ORM作为是一种思想
帮助我们跟踪实体的变化,并将实体的变化翻译成sql脚本,执行到数据库中去,也就是将实体的变化映射到了表的变化
mybatis采用ORM思想解决了实体和数据库映射的问题,对jdbc 进行了封装,屏蔽了jdbc api 底层访问细节
使我们不用与jdbc api 打交道,就可以完成对数据库的持久化操作
Mybatis快速入门:
MyBatis开发步骤:
MyBatis官网地址:http://www.mybatis.org/mybatis-3/
案例需求:通过mybatis查询数据库user表的所有记录,封装到User对象中,打印到控制台上
步骤分析:
代码实现:
创建user数据表:
CREATE DATABASE `mybatis_db`;
USE `mybatis_db`;
CREATE TABLE `user` (
`id` int(11) NOT NULL auto_increment,
`username` varchar(32) NOT NULL COMMENT '用户名称',
`birthday` datetime default NULL COMMENT '生日',
`sex` char(1) default NULL COMMENT '性别',
`address` varchar(256) default NULL COMMENT '地址',PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into `user`(`id`,`username`,`birthday`,`sex`,`address`) values (1,'子
慕','2020-11-11 00:00:00','男','北京海淀'),(2,'应颠','2020-12-12 00:00:00','男','北
京海淀');
导入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>com.lagou</groupId>
<artifactId>mybatis_quickstart</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
<java.version>1.11</java.version>
<maven.compiler.source>1.11</maven.compiler.source>
<maven.compiler.target>1.11</maven.compiler.target>
</properties>
<dependencies>
<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.8</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
</project>
编写User实体 :
package com.lagou.domain;
import java.util.Date;
public class User {
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
public User() {
}
public User(Integer id, String username, Date birthday, String sex, String address) {
this.id = id;
this.username = username;
this.birthday = birthday;
this.sex = sex;
this.address = address;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", birthday=" + birthday +
", sex='" + sex + '\'' +
", address='" + address + '\'' +
'}';
}
}
编写UserMapper映射文件(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">
<mapper namespace="user">
<select id="findAll" resultType="com.lagou.domain.User">
select * from user
</select>
</mapper>
编写MyBatis核心文件(配置文件在资源文件夹下面:sqlMapConfig.xml,resources(maven的)):
<?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="development">
<environment id="development">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql:///mybatis_db"></property>
<property name="username" value="root"></property>
<property name="password" value="123456"></property>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mapper/UserMapper.xml"></mapper>
</mappers>
</configuration>
编写测试类:
package com.lagou.test;
import com.lagou.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 org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class MybatisTest {
@Test
public void mybatisQuickStart() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = build.openSession();
List<User> objects = sqlSession.selectList("user.findAll");
for(User user : objects){
System.out.println(user);
}
sqlSession.close();
}
}
知识小结 :
最后注意:虽然说过了默认的给类赋值,会按照set方法来赋值,但最好还是按照默认的set方法对应名称来进行操作
不要随意修改,因为有些情况,会出现检查名称,使得赋值不了或者出现默认值,更有可能会报错
但基本上对应名称大小写是忽略的(建议不要修改)
Mybatis映射文件概述:
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="userMapper">
<select id="findAll" resultType="com.lagou.domain.User">
select * from user
</select>
<insert id="saveUser" parameterType="com.lagou.domain.User">
insert into user(username,birthday,sex,address) value (#{username},#{birthday},#{sex},#
{address})
</insert>
<update id="updateUser" parameterType="com.lagou.domain.User">
update user set username = #{username},birthday = #{birthday},sex = #{sex},address = #
{address} where id = #{id}
</update>
<delete id="deleteUser" parameterType="java.lang.Integer">
delete from user where id = #{abc}
</delete>
</mapper>
<?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="development">
<environment id="development">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql:///mybatis_db?characterEncoding=utf-8">
</property>
<property name="username" value="root"></property>
<property name="password" value="123456"></property>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mapper/UserMapper.xml"></mapper>
</mappers>
</configuration>
package com.lagou.test;
import com.lagou.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 org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;
public class MybatisTest {
@Test
public void mybatisQuickStart() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = build.openSession();
List<User> objects = sqlSession.selectList("userMapper.findAll");
for(User user : objects){
System.out.println(user);
}
sqlSession.close();
}
@Test
public void testSave() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new
SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
User user = new User();
user.setUsername("自动提交事务");
user.setBirthday(new Date());
user.setSex("男");
user.setAddress("北京海淀");
int insert = sqlSession.insert("userMapper.saveUser", user);
System.out.println(insert);
sqlSession.commit();
sqlSession.close();
}
@Test
public void testUpdate() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new
SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
User user = new User();
user.setId(4);
user.setUsername("lucy");
user.setBirthday(new Date());
user.setSex("女");
user.setAddress("北京朝阳");
sqlSession.update("userMapper.updateUser",user);
sqlSession.commit();
sqlSession.close();
}
@Test
public void testDelete() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new
SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
sqlSession.delete("userMapper.deleteUser",1);
Integer integer = new Integer(1);
sqlSession.commit();
sqlSession.close();
}
}
Mybatis核心文件概述 :
MyBatis核心配置文件层级关系 :
MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息
配置文档的顶层结构如下:
必须按照上面的顺序,因为约束存在,也可以说明是读取顺序
MyBatis常用配置解析 :
environments标签 :
数据库环境的配置,支持多环境配置
properties标签:
实际开发中,习惯将数据源的配置信息单独抽取成一个properties文件,该标签可以加载额外配置的properties:
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///mybatis_db
#如果是本机,localhost:3306可以省略,但后面的/并没有省略,所以上面需要是/mybatis_db
jdbc.username=root
jdbc.password=123
当加载后,会存放对应加载信息,那么可以在加载本配置文件时
查看${}里的值,进行配对,使得使用配对成功的对应值进行连接信息
注意:properties文件一般都是进行键值对配对的,即对应名称和对应变量一致,若不一致,就不会赋值
但是对应驱动的可以不一致,主要是对应驱动会自己注册(要一定的版本)
typeAliases标签:
类型别名是为 Java 类型设置一个短的名字
为了简化映射文件 Java 类型设置,mybatis框架为我们设置好的一些常用的类型的别名:
原来的类型名称配置如下:
配置typeAliases,为com.lagou.domain.User定义别名为user,基本只作用与parameterType和resultType,即他们两个会使用别名
实际上大多数的标签属性都会进行别名替换的,有些特殊的不会,如id等
你可以理解成:之所以需要配置别名,才可简写,是因为不同的包里面可以有相同的类,而java.lang.Integer可以简写成Integer和int(一般来说,他们不区分大小写)
因为这个类是唯一的(他们可以互相转换,一般都是变成int),所以Mybatis就帮我们封装了对应别名,因为默认也是代码进行的
不要当成理所应当
由于这个是写在映射配置的前面,所以会存放好这个别名,当对应映射的对应属性是这个别名时,就会替换的进行反射
<typeAliases>
<package name="com.lagou.domain"/>
</typeAliases>
上面就是对应设置,但之所以可以使用方式二,是因为前面说过
在没有配置前,不同的包里可以有相同的类,那么不可以简写对应类,实际上是Mybatis封装好的
当配置方式一时,我们是指定某个包里的某个类,但是类可以有更多,且我们又要简写,所以我们直接指定一个包,进行批量别名
使得只在一个包里面进行,因为一个包里面是不可以又相同类的,所以就可以使用方式二进行多个类的简写了
当然,如果是其他包且名称相同的且也配置了这个,可能会冲突,一般可能会报错(或者操作第一个配置的),所以别名的处理我们最好使用全限定名称
但是也要注意:别名是别名,是需要出现别名才会转化的,所以正常写也是可以的
mappers标签:
该标签的作用是加载映射的,加载方式有如下几种:
知识小结:
核心配置文件常用配置:
typeAliases标签:设置类型别名:
mappers标签:加载映射配置:
environments标签:数据源环境配置:
Mybatis的API概述:
API介绍:
SqlSession工厂构建器SqlSessionFactoryBuilder
常用API:SqlSessionFactory build(InputStream inputStream)
通过加载mybatis的核心文件的输入流的形式构建一个SqlSessionFactory对象
其中, Resources 工具类,这个类在 org.apache.ibatis.io 包中。Resources 类帮助你从类路径下
文件系统或一个 web URL 中加载资源文件
SqlSession工厂对象SqlSessionFactory :
SqlSessionFactory 有多个个方法创建SqlSession 实例。常用的有如下两个:
设置true,实际上就是不开启事务,那么增删改会启动自带的自动提交,所以对应查询操作是没有任何影响的
因为无论是否开启事务,第一次查询都基本上是表的数据,但是第二次以及以后的查询,若在事务里面,可能不会与表一致了
因为还没有提交,使得表数据不变,但当前事务表已经改变,所以查询的是这个事务表,而不是原表,第一次原表与事务表一致
SqlSession会话对象
SqlSession 实例在 MyBatis 中是非常强大的一个类
在这里你会看到所有执行语句、提交或回滚事务和获取映射器实例的方法
执行语句的方法主要有:
操作事务的方法主要有:
Mybatis基本原理介绍:
Mybatis的dao层开发使用 :
注意:pom.xml只是将对应依赖下载好,放到一个位置,然后引入在项目的包目录下,并自动进行配置
若这时你删掉pom.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="userMapper">
<select id="findAll" resultType="user">
select * from user
</select>
</mapper>
<?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 resource="jdbc.properties"></properties>
<typeAliases>
<package name="com.lagou.domain"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"></transactionManager>
<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>
<mapper resource="mapper/UserMapper.xml"></mapper>
</mappers>
</configuration>
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///mybatis_db?characterEncoding=utf8
#如果是本机,localhost:3306可以省略,但后面的/并没有省略,所以上面需要是/mybatis_db
jdbc.username=root
jdbc.password=123456
package com.lagou.dao;
import com.lagou.domain.User;
import java.io.IOException;
import java.util.List;
public interface IUserDao {
public List<User> findAll() throws IOException;
}
package com.lagou.dao.impl;
import com.lagou.dao.IUserDao;
import com.lagou.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 UserDaoImpl implements IUserDao {
@Override
public List<User> findAll() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = build.openSession();
List<User> objects = sqlSession.selectList("userMapper.findAll");
return objects;
}
}
package com.lagou.domain;
import java.util.Date;
public class User {
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
public User() {
}
public User(Integer id, String username, Date birthday, String sex, String address) {
this.id = id;
this.username = username;
this.birthday = birthday;
this.sex = sex;
this.address = address;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", birthday=" + birthday +
", sex='" + sex + '\'' +
", address='" + address + '\'' +
'}';
}
}
package com.lagou.test;
import com.lagou.dao.impl.UserDaoImpl;
import com.lagou.domain.User;
import org.junit.Test;
import java.io.IOException;
import java.util.List;
public class MybatisText {
@Test
public void test1() throws IOException {
UserDaoImpl userDao = new UserDaoImpl();
List<User> all = userDao.findAll();
for (User user : all) {
System.out.println(user);
}
}
}
传统方式问题思考:
实现类中,存在mybatis模板代码重复
实现类调用方法时,xml中的sql statement 硬编码到java代码中
即userMapper.findAll对应名称不能改变,改变了,就需要java代码也要改变
思考:能否只写接口,不写实现类(里面使用了Mapper.xml),只编写接口和Mapper.xml即可,答:可以
因为在dao(mapper)的实现类中对sqlsession的使用方式很类似,因此mybatis提供了接口的动态代理
代理开发方式:
采用 Mybatis 的基于接口代理方式实现 持久层 的开发
注意:只能是接口,而不能是类,否则会报错,这是他的底层操作的规定的,直接去除了类的操作,即一般是用来当作实现,所以基本只能是接口
而之所以使用接口,而不使用类,是因为接口实现非常方便,易于扩展,所以就不操作类的实现了
那么既然不操作类的实现,自然就不能是类,若是类,则会报错
这种方式是我们后面进入企业的主流
基于接口代理方式的开发只需要程序员编写 Mapper 接口,Mybatis 框架会为我们动态生成实现类的对象
这种开发方式要求我们遵循一定的规范:
注意:在资源文件夹里,无论怎么设置创建如com.lagou.mapper,都是没有层级的
因为在资源文件里面,创建的是文件夹,而不是包,所以上面会看成一个整体文件夹名称,而包会识别" . ",从而分层
要设置文件夹层级,可以com/lagou/mapper来进行创建设置,包不识别" / ",但识别的还是会创建
最后创建的,若是与主文件目录一致,那么就会到里面去,如都是com开头,那么只有一个com(out文件夹里面显示可以看到)
即相当于是同一个目录了
Mapper.xml映射文件中的namespace与mapper接口的全限定名相同
Mapper接口方法名和Mapper.xml映射文件中定义的每个statement的id相同
Mapper接口方法的输入参数类型和mapper.xml映射文件中定义的每个sql的parameterType的类型相同
Mapper接口方法的输出参数类型和mapper.xml映射文件中定义的每个sql的resultType的类型相同
Mapper 接口开发方法只需要程序员编写Mapper 接口(相当于Dao 接口),由Mybatis 框架根据接口
定义创建接口的动态代理对象,代理对象的方法体同上边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="com.lagou.mapper.UserMapper">
<select id="findUserById" parameterType="int" resultType="user">
select * from user where id = #{id}
</select>
</mapper>
<?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 resource="jdbc.properties"></properties>
<typeAliases>
<package name="com.lagou.domain"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"></transactionManager>
<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>
<package name="com.lagou.mapper"></package>
</mappers>
</configuration>
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///mybatis_db?characterEncoding=utf8
#如果是本机,localhost:3306可以省略,但后面的/并没有省略,所以上面需要是/mybatis_db
jdbc.username=root
jdbc.password=123456
package com.lagou.mapper;
import com.lagou.domain.User;
public interface UserMapper {
public User findUserById(int id);
}
package com.lagou.test;
import com.lagou.domain.User;
import com.lagou.mapper.UserMapper;
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.io.InputStream;
public class MybatisText {
@Test
public void test1() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = build.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User userById = mapper.findUserById(6);
System.out.println(userById);
}
}
由此可知,反射的用处重大,在前面也说过,反射就是可以动态的创建对象,所以对于配置文件来说,反射有很大用处
在大多数的框架,基本会用到反射
Mybatis基于接口代理方式的内部执行原理:
我们的持久层现在只有一个接口,而接口是不实际干活的,那么是谁在做查询的实际工作呢?
下面通过追踪源码看一下:
通过追踪源码我们会发现,我们使用的mapper实际上是一个代理对象,是由MapperProxy代理产生的
追踪MapperProxy的invoke方法会发现,其最终调用了mapperMethod.execute(sqlSession, args)
进入execute方法会发现,最终工作的还是sqlSession
所以说,他封装了对应的操作,参数由反射得出的,对应的动态代理,所执行的方法,就算反射出来的默认执行方法
如下面的invoke方法,只要是通过反射出来的,调用对应方法都是这个invoke方法,这个方法传入对应方法名称,进行帮你调用
所以,调用的getMapper()方法,实际上最后还是调用了对应工厂对应自带的对应增删改查方法