原理
一、三层构架包含的三层:
界面层(User Interface layer)、业务逻辑层(Business Logic Layer)、数据访问层(Data LAYER)
界面层:主要功能是接受用户的数据,显示请求的处理结果。使用web页面和用户交互,手机app也就是表示层的,用户在app中操作。业务逻辑在服务器端处理(controller)
业务逻辑层:接收表示传递过来的数据,检查数据,计算机业务逻辑,调用数据访问层获取数据(service包)
数据访问层:与数据库打交道。主要实现对数据的增删改查。将存储的数据库中的数据提交给业务层,同时将业务层处理的数据保存到数据库。(dao层)
二、为什么使用三层构架
结构清晰、耦合度低、各层分工明确
可维护性高、可扩展性高
有利于标准化
开发人员可以关注整个结构中的其中某一层的功能实现
有利于各层逻辑的复用
MyBatis的功能架构是怎样的
我们把Mybatis的功能架构分为三层:
API接口层:提供给外部使用的接口API,开发人员通过这些本地API来操纵数据库。接口层一接收到调用请求就会调用数据处理层来完成具体的数据处理。
数据处理层:负责具体的SQL查找、SQL解析、SQL执行和执行结果映射处理等。它主要的目的是根据调用的请求完成一次数据库操作。
基础支撑层:负责最基础的功能支撑,包括连接管理、事务管理、配置加载和缓存处理,这些都是共用的东西,将他们抽取出来作为最基础的组件。为上层的数据处理层提供最基础的支撑。
四、MyBatis是什么?
是一款优秀的持久层框架,内部封装了JDBC,MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。开发者只需要关注sql语句本身,不需要加载驱动、创建连接、创建statement、关闭连接,资源的繁杂的过程。
MyBati通过xml或注解两种方式来执行各种sql语句配置起来,通过java对象和sql的动态参数进行映射生成最终执行的sql语句,最后由MyBatis框架执行sql并将结果映射为java对象并返回。
五、MyBatis的工作原理
读取MyBatis的工作原理:mybatis-config.xml 为 MyBatis的全局配置文件,配置了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="mysql">
<!--id:数据源的名称-->
<environment id="mysql">
<!--配置事务类型:使用 JDBC 事务(使用 Connection 的提交和回滚)-->
<transactionManager type="JDBC"/>
<!--数据源 dataSource:创建数据库 Connection 对象
type: POOLED 使用数据库的连接池
-->
<dataSource type="POOLED">
<!--连接数据库的四个要素-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/ssm"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<mappers>
<!--告诉 mybatis 要执行的 sql 语句的位置-->
<mapper resource="com/bjpowernode/dao/StudentDao.xml"/>
</mappers>
</configuration>
加载映射文件。映射文件即SQL映射文件,该文件中配置了操作数据库的SQL语句,需要在 MyBatis 配置文件 mybatis-config.xml 中加载。mybatis-config.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:必须有值,自定义的唯一字符串
推荐使用:dao 接口的全限定名称
--> <mapper namespace="com.mei.dao.StudentDao">
<!--
<select>: 查询数据, 标签中必须是 select 语句
id: sql 语句的自定义名称,推荐使用 dao 接口中方法名称,
使用名称表示要执行的 sql 语句
resultType: 查询语句的返回结果数据类型,使用全限定类名
-->
<select id="selectStudents" resultType="com.mei.domain.Student">
<!--要执行的 sql 语句-->
select id,name,email,age from student
</select>
</mapper>
构造会话工厂:通过MyBatis的环境配置信息构建会话工厂SqlSessionFactory
创建会话对象:由会话工厂创建SqlSession对象,该对象中包含执行SQL语句的所有方法
String config = "mybatis-config.xml";
//2.读取配置文件
InputStream in = Resources.getResourceAsStream(config);
//3.创建 SqlSessionFactory 对象,目的是获取 SqlSession
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//4.获取 SqlSession,SqlSession 能执行 sql 语句
SqlSession session = factory.openSession();
//5.执行 SqlSession 的 selectList()
List<Student> studentList =session.selectList("com.mei.dao.StudentDao.selectStudents");
//6.循环输出查询结果
studentList.forEach( student -> System.out.println(student));
//7.关闭 SqlSession,释放资源.SqlSession 接口对象是线程不安全的,所以每次数据库会话结束前,需要马上调用其 close()方法
session.close();
Executor执行器:MyBatis底层定义了一个Executor接口来操作数据库,根据SqlSession传递的参数动态的生成需要执行的SQL语句,同时负责查询缓存的维护。
MappedStatement对象:在Executor接口的执行方法中有一个MappedStatement参数,该对映射信息的封装,用于存储要映射的SQL语句中的ID,参数等信息
传入参数映射:输入参数类型可以是Map、List等集合类型,也可以是基本数据类型和POJO类型。输入参数映射过程类似于JDBC和preparedStatement对象参数的过程(Dao接口)
输出结果映射:输出结果类型可以是Map、List等集合类型,也可以是基本数据类型和POJO类型。输出结果映射过程类似于JDBC对结果集的解析过程。
六、JDBC存在的问题?MyBatis是如何解决这些问题的?
频繁创建数据库连接对象、释放,容易造成系统资源浪费,影响系统性能。可以使用连接池解决这个问题。但是使用jdbc需要自己实现连接池。
解决:在mybatis-config.xml中配置数据链接池,使用连接池管理数据库连接。
sql语句定义、参数设置、结果集处理存在硬编码。实际项目中sql语句变化的可能性较大,一旦发生变化,需要修改JAVA代码,系统需要重新编译,重新发布。不好维护。
解决:将Sql语句配置在XXXXmapper.xml文件中与java代码分离。
使用preparedStatement向占有符号参数存在硬编码,以为sql语句的where条件不一定,可能多也可能少,修改sql还要修改\代码,系统不易维护
解决: Mybatis自动将java对象映射至sql语句。
结果集处理存在重复代码,处理麻烦。如果可以映射成java对象比较方便。
解决:Mybatis自动将sql执行结果映射至java对象。
七、MyBatis优缺点
优点:
基于SQL语句编程,相当灵活,不会对应用程序或者数据库的现有设计造成任何影响,SQL写在XML里,解除sql与程序代码的耦合,便于统一管理;提供XML标签,支持编写动态SQL语句,并可重用
与JDBC相比,减少了50%以上的代码量,消除了JDBC大量冗余的代码,不需要手动开关连接
很好的与各种数据库兼容(因为MyBatis使用JDBC来连接数据库,所以只要JDBC支持的数据库MyBatis都支持)
提供映射标签,支持对象与数据库的ORM字段关系映射;提供对象关系映射标签,支持对象关系组件维护
能够与Spring很好的集成
缺点:
SQL语句的编写工作量较大,尤其当字段多、关联表多时,对开发人员编写SQL语句的功底有一定要求
SQL语句依赖于数据库,导致数据库移植性差,不能随意更换数据库
映射器
一、传递参数
传递多个参数
方法1:顺序传参法
<select id="selectByNameAndAge" resultType="com.mei.domain.Student">
select id,name,email,age from student where name=#{arg0} or age =#{arg1}
</select>
#{}里边的数字代表出入参数的顺序
方法2: @Param注解传参法
接口方法
List<Student> selectMultiParam(@Param("personName") String name,
@Param("personAge") int age);
mapper文件
<select id="selectMultiParam" resultType="com.mei.domain.Student">
select id,name,email,age from student where name=#{personName} or age=#{personAge}
</select>
#{}里面的名称对应的是注解@Param括号里面修饰的名称
方法3:Map参数
接口方法:
List<Student> selectMultiMap(Map<String,Object> map);
mapper文件:
<select id="selectMultiMap" resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student where name=#{myname} or age =#{myage}
</select>
方法4:Java Bean传参法
//创建保存参数值的对象
package com.bjpowernode.vo;
public class QueryParam {
private String queryName;
private int queryAge;
//set ,get 方法
}
//接口方法
List<Student> selectMultiObject(QueryParam queryParam);
//mapper文件
<select id="selectMultiObject" resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student where name=#{queryName} or age
=#{queryAge}
</select>
#{}里面的名称对应的是User类里面的成员属性
二、#{}和${}的区别
#:占位符,告诉Mybatis使用实际的参数值代替。并使用PrepareStatement对象执行SQL语句,#{...}代替sql语句的“?”。这样做更安全,更迅速,通常也是首选做法
$:字符串替换,告诉mybatis使用$包含的“字符串”所替换所在位置。使用Statement把sql语句和${}的内容连接起来。主要用在替换表名,列名,不同列排序等操作
模糊查询like语句该怎么写
模糊查询的实现方式有两种:一是java代码中给查询数据加上“%”;二是在mapper文件sql语句的条件位置上加上“%”
四、Mybatis如何执行批量操作
五、当实体类中的属性名和表中的字段名不一样 ,怎么办
使用列别名和<resultType>
// 创建新的实体类 PrimaryStudent
package com.bjpowernode.domain;
/**
* <p>Description: 实体类 </p>
* <p>Company: http://www.bjpowernode.com
*/
public class PrimaryStudent {
private Integer stuId;
private String stuName;
private Integer stuAge;
// set , get 方法
}
// 接口方法
List<PrimaryStudent> selectUseFieldAlias(QueryParam param);
//mapper 文件:
<select id="selectUseFieldAlias"
resultType="com.bjpowernode.domain.PrimaryStudent">
select id as stuId, name as stuName,age as stuAge
from student where name=#{queryName} or age=#{queryAge}
</select>
通过<resultMap>
来映射字段名和实体类属性名的一一对应的关系
<!-- 创建 resultMap
id:自定义的唯一名称,在<select>使用
type:期望转为的 java 对象的全限定名称或别名
--> <resultMap id="primaryStudentMap"
type="com.bjpowernode.domain.PrimaryStudent">
<!-- 主键字段使用 id -->
<id column="id" property="stuId" />
<!--非主键字段使用 result-->
<result column="name" property="stuName"/>
<result column="age" property="stuAge" />
</resultMap>
<!--resultMap: resultMap 标签中的 id 属性值--> <select id="selectUseDiffResultMap" resultMap="primaryStudentMap">
select id,name,email,age from student
where name=#{queryName} or age=#{queryAge}
</select>
Mapper 编写有哪几种方式?
使用MyBatis的mapper接口调用时有哪些要求
通过Xml映射文件,都会有一个Dao接口与之对应,请问这个Dao接口的工作的原理是什么?Dao接口里的方法,参数不同,方法能重载吗?
Dao接口就是指Mapper接口,接口的全限定名就是映射文件中namespace的值,接口的方法名就是映射文件MappedStatement的id值,接口方法内的参数救赎传递给sql的参数值。
Mapper接口是没有实现类的,当调用接口方法时,接口全限定名+方法名拼接字符串作为key值,可唯一定位MappedStatement
Dao接口里的方法,是不能重载的,因为是全限名+方法名的保存和寻找策略
Dao接口的工作原理是JDK动态代理,MyBatis运行时会使用JDK动态代理为Dao接口生成代理proxy对象,代理对象proxy会拦截接口方法,转而执行MappedStatement所代表的sql,然后将sql执行结果返回。
MyBatis实现一对一,一对多有几种方式,怎么操作的?
有联合查询和嵌套查询。联合查询是几个表联合查询,只查询一次,通过resultMap里面的association /collection 结点配置一对一,一对多的类就可以完成
嵌套查询是先查一个表,根据这个表里面的结果的外键id,去再另外一个表里面查询数据,也是通过配置association,collection,但另外一个表的查询通过select节点配置。
Mybatis动态sql是做什么的?都有哪些动态sql?简述一下动态sql的执行原理?
MyBatis动态sql可以让我们在XML映射文件内,以标签的形式编写动态sql完成逻辑判断和动态拼接sql的功能,Mybatis提供了9种动态sql标签trim|where|set|foreach|if|choose|when|otherwise|bind
其执行的原理为,使用OGNL(Object Graphic Navigation Language)从sql参数对象中计算表达式的值,根据表达式的值动态拼接sql,以此来完成动态SQL的功能
Mybatis是如何进行分页的?分页插件的原理是什么?
MyBatis使用RowBounds对象进行分页,他是针对ResultSet结果集执行的内存分页,而非物理分页可以在sql内直接书写带有物理分页的参数来完成物理分页功能,也可以使用分页插件来完成物理分页
分页插件的基本原理是使用MyBatis提供的插件接口,实现自定义插件,在插件的拦截方法内拦截执行的sql,然后重写sql,根据dialect方言,添加对应的物理分页语句和物理分页参数
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">
2、根元素 <configuration>
3、主要包含内容:定义别名 数据源 mapper文
datasource标签
<dataSource type="POOLED">
<!--连接数据库的四个要素-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url"
value="jdbc:mysql://localhost:3306/ssm?charset=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
事务
使用数据库属性配置文件
类型别名typeAliases
主要使用在<select resultType=”别名”>,mybatis.xml 主配置文件定义别名:
<typeAliases>
<!--
定义单个类型的别名
type:类型的全限定名称
alias:自定义别名
-->
<typeAlias type="com.mei.domain.Student" alias="mystudent"/>
<!--
批量定义别名,扫描整个包下的类,别名为类名(首字母大写或小写都可以)
name:包名
-->
<package name="com.mei.domain"/>
<package name="...其他包"/>
</typeAliases>
mapper.xml 文件,使用别名表示类型
<select id="selectStudents" resultType="mystudent">
select id,name,email,age from student
</select>
映射器
<mapper resource=" " />
使用相对于类路径的资源,从classpath路径查找文件
<mapper resource="com/mei/dao/StudentDao.xml" />
<package name=""/>
指定包下的所有Dao接口
<package name="com.bjpowernode.dao"/>