MyBatis之工作原理,简单实体的增加、修改、删除、查询_Mybatis-原理总结

一、MyBatis之工作原理

MyBatis是一个半自动映射框架。所谓半自动,是相对Hibernate全表映射而言的,MyBatis需要手动匹配提供POJO、SQL和映射关系。

我们知道,JDBC有四个核心对象:
(1)DriverManager,用于注册数据库连接
(2)Connection,与数据库连接对象
(3)Statement/PrepareStatement,操作数据库SQL语句的对象
(4)ResultSet,结果集或一张虚拟表

而MyBatis也有四大核心对象:
(1)SqlSession对象,该对象中包含了执行SQL语句的所有方法。类似于JDBC里面的Connection。
(2)Executor接口,它将根据SqlSession传递的参数动态地生成需要执行的SQL语句,同时负责查询缓存的维护。类似于JDBC里面的Statement/PrepareStatement。
(3)MappedStatement对象,该对象是对映射SQL的封装,用于存储要映射的SQL语句的id、参数等信息。
(4)ResultHandler对象,用于对返回的结果进行处理,最终得到自己想要的数据格式或类型。可以自定义返回类型。

MyBatis的工作原理如下图所示:

img

上面中流程就是MyBatis内部核心流程,每一步流程的详细说明如下文所述:

(1)读取MyBatis的配置文件。mybatis-config.xml为MyBatis的全局配置文件,用于配置数据库连接信息。

(2)加载映射文件。映射文件即SQL映射文件,该文件中配置了操作数据库的SQL语句,需要在MyBatis配置文件mybatis-config.xml中加载。mybatis-config.xml 文件可以加载多个映射文件,每个文件对应数据库中的一张表。

(3)构造会话工厂。通过MyBatis的环境配置信息构建会话工厂SqlSessionFactory。

(4)创建会话对象。由会话工厂创建SqlSession对象,该对象中包含了执行SQL语句的所有方法。

(5)Executor执行器。MyBatis底层定义了一个Executor接口来操作数据库,它将根据SqlSession传递的参数动态地生成需要执行的SQL语句,同时负责查询缓存的维护。

(6)MappedStatement对象。在Executor接口的执行方法中有一个MappedStatement类型的参数,该参数是对映射信息的封装,用于存储要映射的SQL语句的id、参数等信息。

(7)输入参数映射。输入参数类型可以是Map、List等集合类型,也可以是基本数据类型和POJO类型。输入参数映射过程类似于JDBC对preparedStatement对象设置参数的过程。

(8)输出结果映射。输出结果类型可以是Map、List等集合类型,也可以是基本数据类型和POJO类型。输出结果映射过程类似于JDBC对结果集的解析过程。

二、简单实体的增加、修改、删除、查询

1、环境

mybatis-3.2版本,jdk1.8版本,Oracle数据库

2、准备工作

2.1 下载mybatis-3.2,需要引用其中的若干包,包括数据库JDBC驱动包

    mybatis-3.2.0.jarlib/asm-3.3.1.jarlib/cglib-2.2.2.jarlib/commons-logging-1.1.1.jarlib/javassist-3.17.1-GA.jarlib/log4j-1.2.17.jarlib/slf4j-api-1.7.2.jarlib/slf4j-log4j12-1.7.2.jarojdbc6.jar

2.2 项目的目录结构

com.clzhang.mybatis.mapper      MemberUserMapper.java           MyBatis的mapper处理类(非必须)
com.clzhang.mybatis.entity      MemberUserBean.java            MyBatis的entity类
com.clzhang.mybatis             MyBatisTest1.java/MyBatisTest2.java   测试类 resources\config           mybatis-config.xml             MyBatis的配置文件 resources\com\clzhang\mybatis\mapper  MemberUserMapper.xml        MyBatis的mapper配置文件

2.3 假定数据库已经创建,表结构也已经创建,并且有测试数据

CREATE TABLE MEMBER_USER (
ID NUMBER NOT NULL PRIMARY KEY,
NAME VARCHAR2(30),
PERSONMOBILE VARCHAR2(20),
ADDRESS VARCHAR2(255),
AGE NUMBER);CREATE SEQUENCE SEQ_MEMBER_USER;

3、具体步骤

3.1 创建entity类

package com.clzhang.mybatis.entity;public class MemberUserBean {private int id;private String name;private String personMobile;private String address;private int age;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getPersonMobile() {return personMobile;}public void setPersonMobile(String personMobile) {this.personMobile = personMobile;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "MemberUser [id=" + id + ", name=" + name + ", personMobile=" + personMobile + ", address=" + address + ", age=" + age + "]";}
}

3.2 创建Mapper接口(非必须)

package com.clzhang.mybatis.mapper;import java.util.*;
import com.clzhang.mybatis.entity.MemberUserBean;public interface MemberUserMapper {public void insertUser(MemberUserBean user);public void updateUser(MemberUserBean user);public void deleteUser(int id);public MemberUserBean getUserById(int id);public List getUsersByAge(int startAge, int endAge);
}

3.3 创建mybatis-config.xml的配置文件,位置于resources/config目录

<?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> <setting name="cacheEnabled" value="false" /> <setting name="useGeneratedKeys" value="true" /> <setting name="defaultExecutorType" value="REUSE" /> </settings> <typeAliases> <typeAlias alias="MemberUser" type="com.clzhang.mybatis.entity.MemberUserBean"/> </typeAliases> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="oracle.jdbc.driver.OracleDriver"/> <property name="url" value="jdbc:oracle:thin:@127.0.0.1:1521:orcl"/> <property name="username" value="mytest"/> <property name="password" value="test001"/> </dataSource> </environment> </environments> <mappers> <mapper resource="com/clzhang/mybatis/mapper/MemberUserMapper.xml" /> </mappers> 
</configuration>

3.4 创建MemberUserMapper.xml配置文件,位置于:resources\com\clzhang\mybatis\mapper

<?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.clzhang.mybatis.mapper.MemberUserMapper"><!--默认情况下是没有开启缓存的,下条代码是开启二级缓存的,作用如下:1.?映射语句文件中的所有 select 语句将会被缓存。2.?映射语句文件中的所有 insert,update 和 delete 语句会刷新缓存。3.?缓存会使用 Least Recently Used(LRU,最近最少使用的)算法来收回。......--><cache /><!--以单个对象方式返回--><select id="getUserById" resultType="MemberUser" parameterType="int">selectID,NAME,PERSONMOBILE,ADDRESS,AGEFROM MEMBER_USERWHERE ID = #{id}</select><resultMap type="MemberUser" id="userAgeMap">  <id property="id" column="id"/>  <!--有需要做数据库到实体类名称转换的,可以写在这里--><!--<result property="objname" column="dbname"/>--></resultMap>  <!--以List方式返回多个结果--><!--参数名称目前不可以自行指定(无法与Mapper中保持一致),待查--><select id="getUsersByAge" resultMap="userAgeMap" parameterType="int"><![CDATA[selectID,NAME,PERSONMOBILE,ADDRESS,AGEFROM MEMBER_USERWHERE AGE > #{param1} AND AGE < #{param2}]]></select><!--Oracle的实现自增长主键的方式--><insert id="insertUser" parameterType="MemberUser"><selectKey keyProperty="id" resultType="int" order="BEFORE">select SEQ_MEMBER_USER.nextval from DUAL</selectKey>INSERT INTO MEMBER_USER (ID, NAME, PERSONMOBILE, ADDRESS, AGE)VALUES(#{id}, #{name}, #{personMobile}, #{address}, #{age})</insert><update id="updateUser" parameterType="MemberUser">update MEMBER_USER setNAME = #{name},PERSONMOBILE = #{personMobile},ADDRESS = #{address},AGE = #{age}where id = #{id}</update><delete id="deleteUser" parameterType="int">delete from MEMBER_USER where ID = #{id}</delete>
</mapper>

3.5 创建测试类一,调用SqlSession实现CRUD

package com.clzhang.mybatis;import java.io.IOException;
import java.io.Reader;
import java.util.*;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 com.clzhang.mybatis.entity.MemberUserBean;public class MyBatisTest1 {private static final String MYBATIS_CONFIG_FILENAME = "config/mybatis-config.xml";private static SqlSessionFactory sqlSessionFactory;static {Reader reader = null;try {reader = Resources.getResourceAsReader(MYBATIS_CONFIG_FILENAME);} catch (IOException e) {System.out.println(e.getMessage());}// 一旦你创建了 SqlSessionFactory后,SqlSessionFactoryBuilder这个类就不需要存在了。sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);}/*** SqlSessionFactory 应该在你的应用执行期间都存在。没有理由来处理或重新创建它。* * @return*/public static SqlSessionFactory getSqlSessionFactory() {return sqlSessionFactory;}//    @Testpublic void testInert() {// SqlSession 的实例不能被共享,也是线程不安全的。因此最佳的范围是请求或方法范围。SqlSession sqlSession = getSqlSessionFactory().openSession();try {MemberUserBean memberUser = new MemberUserBean();memberUser.setName("李勇");memberUser.setPersonMobile("998877");memberUser.setAddress("江苏某地方");memberUser.setAge(38);int rows = sqlSession.insert("com.clzhang.mybatis.mapper.MemberUserMapper.insertUser", memberUser);if (rows > 0) {System.out.println("您成功插入" + rows + "条数据!");} else {System.out.println("执行插入操作失败!!!");}sqlSession.commit();// 查看新加的对象主键System.out.println("新加对象的id:" + memberUser.getId());} finally {sqlSession.close();}}//    @Testpublic void testUpdate() {SqlSession sqlSession = getSqlSessionFactory().openSession();try {MemberUserBean memberUser = new MemberUserBean();memberUser.setId(5);memberUser.setName("赵五");memberUser.setPersonMobile("12345");memberUser.setAddress("天津上地某公司");memberUser.setAge(29);int rows = sqlSession.update("com.clzhang.mybatis.mapper.MemberUserMapper.updateUser", memberUser);if (rows > 0) {System.out.println("您成功更新" + rows + "条数据!");} else {System.out.println("执行更新操作失败!!!");}sqlSession.commit();} finally {sqlSession.close();}}//    @Testpublic void testDelete() {SqlSession sqlSession = getSqlSessionFactory().openSession();try {int rows = sqlSession.delete("com.clzhang.mybatis.mapper.MemberUserMapper.deleteUser", 5);if (rows > 0) {System.out.println("您成功删除" + rows + "条数据!");} else {System.out.println("执行删除操作失败!!!");}sqlSession.commit();} finally {sqlSession.close();}}//    @Testpublic void getUser() {SqlSession sqlSession = getSqlSessionFactory().openSession();try {MemberUserBean memberUser = sqlSession.selectOne("com.clzhang.mybatis.mapper.MemberUserMapper.getUserById", 1);System.out.println(memberUser.toString());} finally {sqlSession.close();}}//    @Testpublic void getUserByAge() {SqlSession sqlSession = getSqlSessionFactory().openSession();try {Map<String, Object> paramMap = new HashMap<String, Object>();paramMap.put("param1", 20);paramMap.put("param2", 30);List<MemberUserBean> memberUsers = sqlSession.selectList("com.clzhang.mybatis.mapper.MemberUserMapper.getUsersByAge", paramMap);for (MemberUserBean memberUser : memberUsers) {System.out.println(memberUser);}} finally {sqlSession.close();}}
}

3.6 创建测试类二,调用Mapper接口实现CRUD

package com.clzhang.mybatis;import java.io.IOException;
import java.io.Reader;
import java.util.*;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 com.clzhang.mybatis.mapper.MemberUserMapper;
import com.clzhang.mybatis.entity.MemberUserBean;public class MyBatisTest2 {private static final String MYBATIS_CONFIG_FILENAME = "config/mybatis-config.xml";private static SqlSessionFactory sqlSessionFactory;static {Reader reader = null;try {reader = Resources.getResourceAsReader(MYBATIS_CONFIG_FILENAME);} catch (IOException e) {System.out.println(e.getMessage());}// 一旦你创建了 SqlSessionFactory后,SqlSessionFactoryBuilder这个类就不需要存在了。sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);}/*** SqlSessionFactory 应该在你的应用执行期间都存在。没有理由来处理或重新创建它。* * @return*/public static SqlSessionFactory getSqlSessionFactory() {return sqlSessionFactory;}//    @Testpublic void testInert() {// SqlSession 的实例不能被共享,也是线程不安全的。因此最佳的范围是请求或方法范围。SqlSession sqlSession = getSqlSessionFactory().openSession();try {MemberUserBean memberUser = new MemberUserBean();memberUser.setName("李勇");memberUser.setPersonMobile("998877");memberUser.setAddress("江苏某地方");memberUser.setAge(38);MemberUserMapper mapper = sqlSession.getMapper(MemberUserMapper.class);mapper.insertUser(memberUser);sqlSession.commit();// 查看新加的对象主键System.out.println("新加对象的id:" + memberUser.getId());} finally {sqlSession.close();}}//    @Testpublic void testUpdate() {SqlSession sqlSession = getSqlSessionFactory().openSession();try {MemberUserBean memberUser = new MemberUserBean();memberUser.setId(6);memberUser.setName("赵五");memberUser.setPersonMobile("12345");memberUser.setAddress("天津上地某公司");memberUser.setAge(29);MemberUserMapper mapper = sqlSession.getMapper(MemberUserMapper.class);mapper.updateUser(memberUser);sqlSession.commit();} finally {sqlSession.close();}}//    @Testpublic void testDelete() {SqlSession sqlSession = getSqlSessionFactory().openSession();try {MemberUserMapper mapper = sqlSession.getMapper(MemberUserMapper.class);mapper.deleteUser(6);sqlSession.commit();} finally {sqlSession.close();}}//    @Testpublic void getUser() {SqlSession sqlSession = getSqlSessionFactory().openSession();try {MemberUserMapper mapper = sqlSession.getMapper(MemberUserMapper.class);MemberUserBean memberUser = mapper.getUserById(1);System.out.println(memberUser.toString());} finally {sqlSession.close();}}@Testpublic void getUserByAge() {SqlSession sqlSession = getSqlSessionFactory().openSession();try {MemberUserMapper mapper = sqlSession.getMapper(MemberUserMapper.class);List<MemberUserBean> myList = mapper.getUsersByAge(20, 40);for (MemberUserBean entry : myList) {int key = entry.getId();String value = entry.getAddress();System.out.println(key + ":" + value);}} finally {sqlSession.close();}}
}

4、单独测试各个模块

解除注释JUnit各单元,然后键盘输入:alt+shift+X,T,分别进行测试。



Mybatis-原理总结

1.什么是Mybatis?

MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。1、Mybatis是一个半ORM(对象关系映射)框架,底层封装了JDBC,是程序员在开发时只需要关注SQL语句本身,不需要花费精力去处理加载驱动、创建连接、创建statement等繁杂的过程。使得程序员可以花更多的精力放到业务开发中。另外,程序员直接编写原生态sql,严格控制sql执行性能,灵活度高。2、MyBatis 可以使用简单的 XML文件 或注解方式来配置和映射原生信息,将 POJO映射成数据库中的记录,避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。3、通过xml 文件或注解的方式将要执行的各种 statement 配置起来,并通过java对象和 statement中sql的动态参数进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射为java对象并返回。(从执行sql到返回result的过程)。

Mybaits的优点:

1、基于SQL语句编程,相当灵活,不会对应用程序或者数据库的现有设计造成任何影响,SQL写在XML里,解除sql与程序代码的耦合,便于统一管理;提供XML标签,支持编写动态SQL语句,并可重用。2、与JDBC相比,减少了50%以上的代码量,消除了JDBC大量冗余的代码,不需要手动开关连接;3、很好的与各种数据库兼容(因为MyBatis使用JDBC来连接数据库,所以只要JDBC支持的数据库MyBatis都支持)。4、能够与Spring很好的集成;5、提供映射标签,支持对象与数据库的ORM字段关系映射;提供对象关系映射标签,支持对象关系组件维护。

3 .MyBatis框架的缺点:

1、SQL语句的编写工作量较大,尤其当字段多、关联表多时,对开发人员编写SQL语句的功底有一定要求。2、SQL语句依赖于数据库,导致数据库移植性差,不能随意更换数据库。

4.MyBatis框架适用场合:

1、MyBatis专注于SQL本身,是一个足够灵活的DAO层解决方案。2、对性能的要求很高,或者需求变化较多的项目,如互联网项目,MyBatis将是不错的选择。

5.MyBatis与Hibernate有哪些不同?

1、Mybatis是一个半自动的ORM框架,在查询关联对象或关联集合对象时,需要手动编写sql语句来完成;Hibernate是全自动ORM映射工具,查询关联对象或者关联集合对象时,可以根据对象关系模型直接获取,不需要编写sql.2、Mybatis直接编写原生态sql,可以严格控制sql执行性能,灵活度高,非常适合对性能要求高,需求变化频繁的项目;但是如果涉及到较多的字段或者关联多表时,sql语句编写量大且对开发人的sql语句编写功底要求高。3、Hibernate对象/关系映射能力强,数据库无关性好,适合需求变化不大的项目,使用hibernate开发可以节省很多代码,提高效率。

二、架构

我们把Mybatis的功能架构分为三层:

(1)API接口层:提供给外部使用的接口API,开发人员通过这些本地API来操纵数据库。接口层一接收到调用请求就会调用数据处理层来完成具体的数据处理。

(2)数据处理层:负责具体的SQL查找、SQL解析、SQL执行和执行结果映射处理等。它主要的目的是根据调用的请求完成一次数据库操作。

(3)基础支撑层:负责最基础的功能支撑,包括连接管理、事务管理、配置加载和缓存处理,这些都是共用的东西,将他们抽取出来作为最基础的组件。为上层的数据处理层提供最基础的支撑。

img

img

img

img

img

1、SqlSessionFactoryBuilder【全局的对象】

每一个MyBatis的应用程序的入口是:SqlSessionFactoryBuilder。它的作用是通过XML配置文件创建Configuration对象(当然也可以在程序中自行创建),然后通过build方法创建SqlSessionFactory对象。

2、SqlSessionFactory【全局的对象】

每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为中心的。SqlSessionFactory是由SqlSessionFactoryBuilder 从 XML 配置文件或通过Java的方式构建出 的实例,主要功能是创建SqlSession(会话)对象;SqlSessionFactory对象一个必要的属性是Configuration对象;SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,建议使用单例模式或者静态单例模式。一个SqlSessionFactory对应配置文件中的一个环境(environment),如果你要使用多个数据库就配置多个环境分别对应一个SqlSessionFactory。

3、 SqlSession

作为MyBatis工作的主要顶层API,表示和数据库交互的会话,完成必要数据库增删改查功能。SqlSession通过调用api的Statement ID找到对应的MappedStatement对象。SqlSession是一个接口,它有2个实现类,分别是DefaultSqlSession(默认使用)以及SqlSessionManager;默认使用DefaultSqlSession,它有两个必须配置的属性:Configuration和Executor,SqlSession通过内部存放的执行器(Executor)来对数据进行CRUD。由于不是线程安全的,所以SqlSession对象的作用域需限制方法内;每一次操作完数据库后都要调用close对其进行关闭,官方建议通过try-finally来保证总是关闭SqlSession。

4、 Executor

MyBatis执行器,是MyBatis 调度的核心。Executor对象在创建Configuration对象的时候创建,并且缓存在Configuration对象里。Executor:负责SQL语句的生成,调用StatementHandler访问数据库,查询缓存的维护;Executor(负责动态SQL的生成和查询缓存的维护)将MappedStatement对象进行解析,sql参数转化、动态sql拼接,生成jdbc Statement对象;**Executor(执行器)接口有两个实现类,其中BaseExecutor有三个继承类分别是BatchExecutor(重用语句并执行批量更新),ReuseExecutor(重用预处理语句prepared statements),SimpleExecutor(普通的执行器)。

5、 StatementHandler

封装了JDBC Statement操作,负责对JDBCstatement的操作,如设置参数、将Statement结果集转换成List集合,是真正访问数据库的地方,并调用ResultSetHandler处理查询结果。

6、ResultSetHandler

ParameterHandler 负责将用户传递的参数转换成JDBC Statement 所需要的参数ResultSetHandler负责将JDBC返回的ResultSet结果集对象转换成List类型的集合;处理查询结果。TypeHandler负责java数据类型和jdbc数据类型之间的映射和转换7、 MappedStatement :

MappedStatement就是用来存放我们SQL映射文件中的信息包括sql语句,输入参数,输出参数等等。一个SQL节点对应一个MappedStatement对象。借助MappedStatement中的结果映射关系,将返回结果转化成HashMap、JavaBean等存储结构并返回。

8、 SqlSource

负责根据用户传递的parameterObject,动态地生成SQL语句,将信息封装到BoundSql对象中,并返回

BoundSql表示动态生成的SQL语句以及相应的参数信息ConfigurationMyBatis所有的配置信息都维持在Configuration对象之中三, Mybatis面试题

1: #{}和${}的区别是什么?

1-a) #{}是占位符,可以接收参数,可以是简单类型也可以是pojo 类型;使用#{}可以有效地防止SQL注入,提高系统安全性。Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值;

{}时,就是把${}替换成变量的值。

3: 模糊查询like语句该怎么写?

第1种:在Java代码中添加sql通配符。第2种:在sql语句中拼接通配符,会引起sql注入

4:通常一个Xml映射文件,都会写一个Dao接口与之对应,请问,这个Dao接口的工作原理是什么?Dao接口里的方法,参数不同时,方法能重载吗?

Dao接口即Mapper接口。接口的全限名,就是映射文件中的namespace的值;接口的方法名,就是映射文件中Mapper的Statement的id值;接口方法内的参数,就是传递给sql的参数。

Mapper接口是没有实现类的,当调用接口方法时,接口全限名+方法名拼接字符串作为key值,可唯一定位一个MapperStatement。在Mybatis中,每一个 、、、 标签,都会被解析为一个MapperStatement对象。

举例: com.mybatis3.mappers.StudentDao.findStudentById ,可以唯一找到namespace为 com.mybatis3.mappers.StudentDao 下面 id 为 findStudentById 的 MapperStatement。

Mapper接口里的方法,是不能重载的,因为是使用 全限名+方法名 的保存和寻找策略。Mapper 接口的工作原理是JDK动态代理,Mybatis运行时会使用JDK动态代理为Mapper接口生成代理对象proxy,代理对象会拦截接口方法,转而执行MapperStatement所代表的sql,然后将sql执行结果返回。

5:Mybatis是如何进行分页的?分页插件的原理是什么?

Mybatis使用RowBounds对象进行分页,它是针对ResultSet结果集执行的内存分页,而非物理分页。可以在sql内直接书写带有物理分页的参数来完成物理分页功能,也可以使用分页插件来完成物理分页。

分页插件的基本原理是使用Mybatis提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的sql,然后重写sql,根据dialect方言,添加对应的物理分页语句和物理分页参数。

6:Mybatis是如何将sql执行结果封装为目标对象并返回的?都有哪些映射形式?

第一种:通过 <resultMap> 来映射字段名和实体类属性名的一一对应的关系。第二种是使用sql列的别名功能,让字段名的别名和实体类的属性名一致。

有了列名与属性名的映射关系后,Mybatis通过反射创建对象,同时使用反射给对象的属性逐一赋值并返回,那些找不到映射关系的属性,是无法完成赋值的。

8:如何获取自动生成的(主)键值?

insert 方法总是返回一个int值 ,这个值代表的是插入的行数。如果采用自增长策略,自动生成的键值在 insert 方法执行完后可以被设置到传入的参数对象中。

select last_insert_id(); insert into stu2.user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address}); 9:在mapper中如何传递多个参数?

1、第一种:DAO层的函数2、第二种: 使用 @param 注解:然后,就可以在xml像下面这样使用(推荐封装为一个map,作为单个参数传递给mapper):3、第三种:多个参数封装成map

10:Mybatis动态sql有什么用?执行原理?有哪些动态sql?

Mybatis动态sql可以在Xml映射文件内,以标签的形式编写动态sql,执行原理是根据表达式的值 完成逻辑判断并动态拼接sql的功能。

Mybatis提供了9种动态sql标签: trim|where|set|foreach|if|choose|when|otherwise|bind。

11:Xml映射文件中,除了常见的select|insert|updae|delete标签之外,还有哪些标签?

答: <resultMap>、<parameterMap>、<sql>、<include>、<selectKey> ,加上动态sql的9个标签,其中 为sql片段标签,通过 标签引入sql片段, 为不支持自增的主键生成策略标签。

12:Mybatis的Xml映射文件中,不同的Xml映射文件,id是否可以重复?

不同的Xml映射文件,如果配置了namespace,那么id可以重复;如果没有配置namespace,那么id不能重复;

原因就是namespace+id是作为Map <String,MapperStatement> 的key使用的,如果没有namespace,就剩下id,那么,id重复会导致数据互相覆盖。有了namespace,自然id就可以重复,namespace不同,namespace+id自然也就不同。

14: 一对一、一对多的关联查询 ?

14-1: MyBatis实现一对一有几种方式?具体怎么操作的?

有联合查询和嵌套查询;联合查询是几个表联合查询,只查询一次, 通过在resultMap里面配置association节点配置一对一的类就可以完成;嵌套查询是先查一个表,根据这个表里面的结果的 外键id,去再另外一个表里面查询数据,也是通过association配置,但另外一个表的查询通过select属性配置。

14-2: MyBatis实现一对多有几种方式,怎么操作的?

有联合查询和嵌套查询。联合查询是几个表联合查询,只查询一次,通过在resultMap里面的collection节点配置一对多的类就可以完成;嵌套查询是先查一个表,根据这个表里面的 结果的外键id,去再另外一个表里面查询数据,也是通过配置collection,但另外一个表的查询通过select节点配置。

15: Mybatis是否支持延迟加载?如果支持,它的实现原理是什么?

答:Mybatis仅支持association关联对象和collection关联集合对象的延迟加载,association指的就是一对一,collection指的就是一对多查询。在Mybatis配置文件中,可以配置是否启用延迟加载lazyLoadingEnabled=true|false。

它的原理是,使用CGLIB创建目标对象的代理对象,当调用目标方法时,进入拦截器方法,比如调用a.getB.getName,拦截器invoke方法发现a.getB是值,那么就会单独发送事先保存好的查询关联B对象的sql,把B查询上来,然后调用a.setB(b),于是a的对象b属性就有值了,接着完成a.getB.getName方法的调用。这就是延迟加载的基本原理。

当然了,不光是Mybatis,几乎所有的包括Hibernate,支持延迟加载的原理都是一样的。

16: Mybatis的一级、二级缓存:

1)一级缓存: 基于 PerpetualCache 的 HashMap 本地缓存,其存储作用域为 Session,当 Session flush 或 close 之后,该 Session 中的所有 Cache 就将清空,默认打开一级缓存。

2)二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap 存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache。默认不打开二级缓存,要开启二级缓存,使用二级缓存属性类需要实现Serializable序列化接口(可用来保存对象的状态),可在它的映射文件中配置 ;

3)对于缓存数据更新机制,当某一个作用域(一级缓存 Session/二级缓存Namespaces)的进行了C/U/D 操作后,默认该作用域下所有 select 中的缓存将被 clear。

17: 什么是MyBatis的接口绑定?有哪些实现方式?

接口绑定,就是在MyBatis中任意定义接口,然后把接口里面的方法和SQL语句绑定, 我们直接调用接口方法就可以,这样比起原来了SqlSession提供的方法我们可以有更加灵活的选择和设置。

接口绑定有两种实现方式:一种是通过注解绑定,就是在接口的方法上面加上 @Select、@Update等注解,里面包含Sql语句来绑定;另外一种就是通过xml里面写SQL来绑定, 在这种情况下,要指定xml映射文件里面的namespace必须为接口的全路径名。当Sql语句比较简单时候,用注解绑定, 当SQL语句比较复杂时候,用xml绑定,一般用xml绑定的比较多。

18: 使用MyBatis的mapper接口调用时有哪些要求?

1、Mapper接口方法名和mapper.xml中定义的每个sql的id相同;2、Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同;3、Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同;4、Mapper.xml文件中的namespace即是mapper接口的类路径。

19:Mapper编写有哪几种方式?

第一种:接口实现类继承SqlSessionDaoSupport:使用此种方法需要编写mapper接口,mapper接口实现类、mapper.xml文件。1、在sqlMapConfig.xml中配置mapper.xml的位置2、定义mapper接口3、实现类集成SqlSessionDaoSupport mapper方法中可以this.getSqlSession进行数据增删改查。4、spring 配置

第二种:使用 org.mybatis.spring.mapper.MapperFactoryBean :1、在sqlMapConfig.xml中配置mapper.xml的位置,如果mapper.xml和mappre接口的名称相同且在同一个目录,这里可以不用配置2、定义mapper接口:3、mapper.xml中的namespace为mapper接口的地址4、mapper接口中的方法名和mapper.xml中的定义的statement的id保持一致5、Spring中定义

第三种:使用mapper扫描器:1、mapper.xml文件编写:mapper.xml中的namespace为mapper接口的地址;mapper接口中的方法名和mapper.xml中的定义的statement的id保持一致;如果将mapper.xml和mapper接口的名称保持一致则不用在sqlMapConfig.xml中进行配置。2、定义mapper接口:注意mapper.xml的文件名和mapper的接口名称保持一致,且放在同一个目录3、配置mapper扫描器:4、使用扫描器后从spring容器中获取mapper的实现对象。

20: 简述Mybatis的插件运行原理,以及如何编写一个插件。

答:Mybatis仅可以编写针对ParameterHandler、ResultSetHandler、StatementHandler、Executor这4种接口的插件,Mybatis使用JDK的动态代理,为需要拦截的接口生成代理对象以实现接口方法拦截功能,每当执行这4种接口对象的方法时,就会进入拦截方法,具体就是InvocationHandler的invoke方法,当然,只会拦截那些你指定需要拦截的方法。

编写插件:实现Mybatis的Interceptor接口并复写intercept方法,然后在给插件编写注解,指定要拦截哪一个接口的哪些方法即可,记住,别忘了在配置文件中配置你编写的插件。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/555255.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL优化:如何避免回表查询?_什么是索引覆盖?

数据库表结构&#xff1a; create table user (id int primary key,name varchar(20),sex varchar(5),index(name) )engineinnodb;select id,name where nameshenjianselect id,name,sex where nameshenjian多查询了一个属性&#xff0c;为何检索过程完全不同&#xff1f; 什…

mysql提示Column count doesn‘t match value count at row 1错误

我们在对数据库进行添加信息时可能会遇到如下错误&#xff1a; Column count doesn’t match value count at row 1 该错误的意思是传入表的字段数和values值的个数不一样 我总结了一下&#xff0c;主要有3个易错点&#xff1a; 1.要传入表中的字段数和values后面的值的个数不…

java 阅发布模式_redis发布订阅模式

一 前言虽然有消息队列&#xff0c;我们还是要了解一下redis发布订阅模式哟&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;二发布订阅模式PUBLISH 命令向通道发送信息&#xff0c;此客户端称为publisher 发布者&#xff1b;SUBSCRIBE 向命令通道订阅信息&#…

把实体 转为json 数据格式---jackson 的详细用法_Jackson快速入门

首先介绍三个注解&#xff1a; JsonAutoDetect (method/field):作用于方法或字段&#xff0c;用来表明&#xff0c;当生成json的时候忽略有该annotation的方法或字段 JsonIgnore 过滤不需要转成json的属性 JsonIgnoreProperties 主要用于过滤掉一些不需要的属性 以上三个注…

java 类的加载顺序_Java 中类的加载顺序

这其实是去年校招时我遇到的一道阿里巴巴的笔试题(承认有点久远了-。-)&#xff0c;嗯&#xff0c;如果我没记错的话&#xff0c;当时是作为Java方向的一道选做大题。当然题意没有这么直白&#xff0c;题目只要求你写出程序运行后所有System.out.println的输出结果&#xff0c;…

Jackson转换json大写_关于jackson转化json的原理_jackson序列化和反序列化Json

背景 web工程中&#xff0c;数据交互是不可避免的&#xff0c;相比xml&#xff0c;json是现在流行的数据交互。 在调试接口中&#xff0c;发现返回字段的大小写不是我所期望的&#xff0c;原本应该返回的nNum字段变成了nnum&#xff0c;这样就导致和前端约定的有出入了。 ja…

svn利用TortoiseSVN忽略文件或文件夹(目录)

忽略已经版本控制的文件 如果你不小心添加了一些应该被忽略的文件&#xff0c;你如何将它们从版本控制中去除而不会丢失它们&#xff1f;或许你有自己的IDE配置文件&#xff0c;不是项目的一部分&#xff0c;但将会花费很多时间使之按照自己的方式工作。 如果你还没有提交&am…

SpringMVC 参数绑定详解

概述 记得之前跟前端同事联调接口的时候&#xff0c;后端SpringMVC需要接收数组类型的参数&#xff0c;然后跟前端说需要传数组类型过来。后来前端童鞋传了数组&#xff0c;但是后端接收不成功&#xff0c;联调失败。那时候由于时间关系没有仔细研究这块&#xff0c;当时想了个…

java 连接远程服务器_java实现连接远程服务器并执行命令的基本原理

一、所需jar包需要借助Ganymed SSH的jar包: ganymed-ssh2-build210.jar二、实现原理Ganymed SSH-2 java在整个访问过程中担当SSH的客户端&#xff0c;由于Linux系统自带SSH服务&#xff0c;所以可以直接访问Linux系统并执行相关命令&#xff0c;而 Windows系统则需要首先安装S…

SpringMVC接收基本类型和包装类型

先看一个示例&#xff1a; 注意这两个参数都没有加RequestParam注解。 测试&#xff1a; 直接报错。即没有加RequestParam注解&#xff0c;基本数据类型参数是必填的。 再测试&#xff1a; 直接返回null&#xff0c;也就是说包装类型参数&#xff0c;没有加RequestParam注解&…

SpringMVC 【参数绑定详讲、默认支持参数类型、自定义参数绑定、RequestParam 注解】

SpringMVC 第四篇【参数绑定详讲、默认支持参数类型、自定义参数绑定、RequestParam 注解】 参数绑定 我们在 Controller 使用方法参数接收值&#xff0c;就是把 web 端的值给接收到 Controller 中处理&#xff0c;这个过程就叫做参数绑定… 默认支持的参数类型 从上面的用…

MySQL中 IS NULL、IS NOT NULL、不等于, 能用上索引吗?

MySQL的WHERE子句中包含 IS NULL、IS NOT NULL、! 这些条件时便不能使用索引查询&#xff0c;只能使用全表扫描。 告诉大家结论&#xff1a; MySQL中决定使不使用某个索引执行查询的依据就是成本够不够小&#xff0c;如果null值很多&#xff0c;还是会用到索引的。 自己做了个…

Java EE 企业网站_基于jsp的企业网站系统-JavaEE实现企业网站系统 - java项目源码...

基于jspservletpojomysql实现一个javaee/javaweb的企业网站系统, 该项目可用各类java课程设计大作业中, 企业网站系统的系统架构分为前后台两部分, 最终实现在线上进行企业网站系统各项功能,实现了诸如用户管理, 登录注册, 权限管理等功能, 并实现对各类企业网站系统相关的实体…

MySQL创建联合索引,字段的先后顺序,对查询的影响分析

文章目录前言最左匹配原则为什么会有最左前缀呢&#xff1f;联合索引的存储结构联合索引字段的先后顺序b树可以存储的数据条数总结前言 ​ 对于联合索引我们知道&#xff0c;在使用的时候有一个最左前缀的原则&#xff0c;除了这些呢&#xff0c;比如字段放置的位置&#xff0…

php oracle 操作 sql语句中能不能添加数组_如何在PHP中使用Oracle数据库_php

在php3.0以上版本中&#xff0c;php内置了几乎目前所有的数据库处理函数&#xff0c;包括oracle;在本文中我们通过一个实例来介绍了如何使用这些函数来操作Oracle数据库。PHP提供了2大类API(应用程序接口)来操作Oracle数据库。一个是标准的Oracle处理函数(ORA) 另一个是Oracle …

mysql where过滤条件中and连接的两个条件的顺序不必和建立的联合索引的字段顺序一致_mysql and 顺序_mysql执行过程以及顺序

mysql中and的判断顺序 select * from a join b on 条件一 and 条件二条件一和二都是判断 id 字段&#xff0c; 条件一和条件二哪个先执行&#xff1f; 解析器会自动选择最优的流程执行的 这两个都是平级条件&#xff0c;理论上是没有先后顺序的&#xff01; 没有顺序&#xff…

MySQL优化器_MySQL查询优化器

MySQL优化器 MySQL架构图 讲到MySQL&#xff0c;就绕不开他的架构图。MySQL是一个经典的C/S架构。服务器这边分两层&#xff1a;第一层是Server层&#xff0c;第二层是存储引擎。Server层处理主要的业务操作流程&#xff0c;但不关心具体的存储逻辑。存储逻辑由存储引擎层去…

MySQL性能优化(一)MySQL中SQL语句是如何执行的?

该篇章将开始整理MySQL的优化&#xff0c;不过开始之前&#xff0c;我们想了解清楚那就是MySQL是怎么执行的。 文章目录1.MySQL驱动2.应用系统数据库连接池3.MySQL数据库连接池4.SQL执行过程4.1.线程监听&#xff1a;监听网络请求中的SQL语句4.2.SQL接口&#xff1a;负责处理接…

2023_Spark_实验三十三:配置Standalone模式Spark3.4.2集群

实验目的&#xff1a;掌握Spark Standalone部署模式 实验方法&#xff1a;基于centos7部署Spark standalone模式集群 实验步骤&#xff1a; 一、下载spark软件 下载的时候下载与自己idea里对应版本的spark News | Apache Spark 选择任意一个下载即可 - spark 3.4.1 - spark …

MySQL性能优化(二)InnoDB之日志文件

文章目录1.MySQL日志记录文件1.1.回顾SQL语句的执行1.2.InnoDB内存结构&#xff1a;缓冲池1.3.记录日志&#xff1a;Undo和Redo1.3.1.Undo日志文件&#xff1a;记录数据修改前的值1.3.2.Redo日志文件&#xff1a;记录数据即将修改值1.3.3.Undo和Redo的区别&#xff08;记录、前…