1Mybatis中#和$的区别?

1.1背记



符号

#

$

说明

# 占位符是使用预编译的方式进行参数传递,并自动进行参数类型转换和防止SQL注入攻击

$ 占位符是使用字符串拼接的方式进行参数传递, ${} 用于必须构建动态SQL语句的情况

1.2理解

MyBatis中, 井号(#)和美元符号($)是两种不同的参数占位符使用方式。

1.2.1井号(#)

使用预编译的方式进行参数传递。在SQL语句中,使用 # 可以将参数值安全地替换到SQL语句中,并自动进行参数类型转换和防止SQL注入攻击。使用 # 占位符时,MyBatis会将参数值作为一个整体传递给数据库,因此可以有效地防止SQL注入问题。
SELECT * FROM users WHERE id = #{userId} 示例SQL:
在上述示例中,#{userId}会被替换为具体的参数值,并且会根据参数类型进行合适的转换。

1.2.2美元符号($)

使用字符串拼接的方式进行参数传递。在SQL语句中,使用$可以将参数值直接拼接到SQL语句中,不进行预编译和参数类型转换。使用$占位符时,需要注意潜在的安全风险,因为参数值直接拼接到SQL语句中,可能会导致SQL注入攻击。
SELECT * FROM users WHERE id = ${userId} 示例SQL
在上述示例中, ${userId} 会被替换为具体的参数值,但不会进行参数类型转换和安全检查。

1.3总结

使用井号(#)占位符可以提供更安全和可靠的参数传递方式,适用于大多数情况。
使用美元符号($)占位符可以提供更灵活的参数传递方式,但需要注意安全性和潜在的SQL注入问题。
在选择使用井号(#)还是美元符号($)时,需要根据具体的需求和安全考虑来决定。
一般来说,推荐使用 # 占位符,除非有特殊的需求需要使用 $ 占位符。


2Mybatis的编程步骤是什么样的?

MyBatis的编程步骤主要包括以下几个环节:
  1. 配置数据库连接:需要配置数据库连接信息,这通常在MyBatis的全局配置文件 mybatis-config.xml 中完成。这个配置文件包含了数据库连接、事务管理、别名等重要信息。
  2. 创建映射文件:映射文件(mapper.xml)是MyBatis的核心部分,它定义了SQL语句和Java对象之间的映射关系。在这一步中,你需要编写SQL语句,并通过映射文件将这些语句与Java对象关联起来。
  3. 编写接口:在MyBatis中,需要创建一个接口,该接口将定义与数据库交互的方法。这些方法不需要实现,因为MyBatis会在运行时动态生成它们的实现。
  4. 编写实体类:实体类用于表示数据库中的表,它们通常与数据库表一一对应,包含表中字段对应的属性。
  5. 执行SQL操作:通过调用在第一步中创建的接口方法,可以执行SQL操作,如查询、插入、更新或删除数据。MyBatis会处理这些方法调用,将其转换为实际的SQL语句执行。
  6. 结果映射:MyBatis会自动将SQL查询的结果映射到Java对象中,这个过程可以通过配置映射文件中的结果映射来完成。
  7. 释放资源:在使用完数据库连接后,需要关闭连接和释放其他相关资源,以确保系统的稳定性和性能。
总的来说,MyBatis通过提供一种半自动化的ORM实现,简化了JDBC的繁琐过程,使得开发者可以更加专注于SQL语句的编写和优化。

3JDBC编程有哪些不足之处,MyBatis是如何解决这些问题的?

MyBatis作为一个优秀的持久层框架,它简化了JDBC操作数据库的过程。MyBatis通过提供XML映射文件或者注解的方式,让开发者只需要关注SQL本身,而无需处理诸如注册驱动、创建连接、创建statement、设置参数、结果集检索等JDBC中的繁杂过程代码。以下是JDBC编程的一些不足之处以及MyBatis是如何解决这些问题的:
  1. 繁琐的代码:JDBC编程需要编写大量的重复代码,包括连接数据库、创建和释放资源、处理结果集等。这使得代码冗长、难以维护和理解。MyBatis通过提供一个简洁的配置文件和映射文件,将数据库操作的细节抽象出来,使得开发者只需关注SQL语句和参数映射,大大减少了繁琐的代码量。
  2. SQLJava代码的耦合:在JDBC编程中,SQL语句通常直接嵌入在Java代码中,导致SQLJava代码紧密耦合,不易于维护和修改。MyBatis使用了面向SQL的思想,将SQL语句与Java代码分离,通过映射文件将SQL语句与Java对象进行映射,使得SQLJava代码解耦,提高了代码的可维护性和可读性。
  3. 手动参数设置和结果集处理:在JDBC编程中,需要手动设置参数并处理结果集,包括类型转换、结果集遍历等,增加了开发的工作量和出错的可能性。MyBatis通过提供参数映射和结果集映射的功能,自动处理参数设置和结果集转换,开发者只需定义映射关系,MyBatis会自动完成参数设置和结果集处理,简化了开发过程。
  4. 缺乏对象关系映射(ORM)支持:JDBC编程需要手动将数据库查询结果映射到Java对象中,缺乏对对象关系映射的支持,增加了开发的复杂性。MyBatis提供了强大的对象关系映射(ORM)功能,可以将查询结果自动映射到Java对象中,支持一对一、一对多、多对一等复杂的关系映射,简化了数据操作的过程。5. 缺乏缓存支持:JDBC编程没有内置的缓存机制,每次查询都需要访问数据库,降低了性能。MyBatis提供了一级缓存和二级缓存的支持。一级缓存是在同一个会话中的缓存,可以减少对数据库的访问;二级缓存是在多个会话中的缓存,可以共享缓存结果,提高了查询性能。
总的来说,MyBatis通过提供简洁的配置和映射文件、解耦SQLJava代码、自动处理参数和结果集、支持对象关系映射和缓存等功能,弥补了JDBC编程的不足之处,提供了更便捷、高效和可维护的数据库访问解决方案。

4使用MyBatisMapper接口调用时有哪些要求?

使用MyBatismapper接口调用时,需要满足以下几个要求:
  1. 方法名匹配:Mapper接口中的方法名需要与mapper.xml文件中定义的SQL语句的id相同。
  2. 输入参数类型匹配:Mapper接口方法的输入参数类型应与mapper.xml中定义的SQL语句的parameterType类型一致。
  3. 输出参数类型匹配:Mapper接口方法的返回类型应与mapper.xml中定义的SQL语句的resultType类型相匹配。
  4. 正确配置namespace:Mapper.xml文件中的namespace应与mapper接口的全限定类名(类路径)相对应。

5Mybatis中一级缓存与二级缓存?

5.1背记

MyBatis中,存在一级缓存和二级缓存两种缓存机制

5.1.1一级缓存是SqlSession级别的缓存

一级缓存在MyBatis中发挥着减少数据库访问次数和提高数据访问效率的作用。它是默认开启且无法关闭的,作用于单个SqlSession内部

5.1.2二级缓存是mapper级别的缓存

二级缓存的作用域是mapper的同一个namespace,需要手动开启的,它不依赖于单个SqlSession,而是跨SqlSession的。这意味着不同的SqlSession如果执行相同的namespace下的SQL语句,且传递的参数也相同,那么第一次执行完毕后,数据会被写入缓存,第二次查询时会直接从缓存中获取数据,而不再访问底层数据库。这样可以显著提高数据查询的效率,减少数据库的压力。

5.2理解

在 MyBatis 中,存在一级缓存和二级缓存两种缓存机制。

5.2.1一级缓存

一级缓存是 MyBatis 默认开启的缓存机制,也被称为本地缓存。一级缓存的作用范围是在同一个 SqlSession 内部,即在同一个会话期间,多次执行相同的查询语句,第一次查询结果会被缓存到一级缓存中,后续的查询会直接从缓存中获取结果,而不再去查询数据库。一级缓存是基于对象引用的方式实现的,因此在同一个会话期间,如果对查询结果进行了修改(例如更新、插入、删除等操作),则会清空一级缓存,以保证数据的一致性。

5.2.2二级缓存

二级缓存是 MyBatis 的全局缓存机制,作用范围是在同一个 Mapper 的 namespace中,即多个 SqlSession 共享同一个 Mapper 的缓存。
二级缓存可以跨越多个会话,当多个会话执行相同的查询语句时,第一个会话的查询结果会被缓存到二级缓存中,后续的会话可以直接从缓存中获取结果,而不再去查询数据库。
二级缓存是基于序列化的方式实现的,因此要求缓存的对象必须是可序列化的。
默认情况下,二级缓存是关闭的,需要在 Mapper 的配置文件中显式配置开启。

5.2.3需要注意的是

一级缓存和二级缓存是独立的,互不影响。
二级缓存是可选的,可以根据需要选择是否开启。
二级缓存的使用需要注意数据的一致性和并发访问的问题,特别是在多线程环境下。

5.3总结

一级缓存是在同一个会话期间的缓存,而二级缓存是在同一个 Mapper 的命名空间中的缓存。一级缓存是默认开启的,二级缓存是可选的。在实际应用中,可以根据需求选择合适的缓存机制来提高查询性能。

6MyBatisinsert插入操作时如何返回主键ID?

6.1背记

MyBatis中,要使insert插入操作返回主键ID,可以通过以下两种方式实现:
  1. 使用 useGeneratedKeys keyProperty 属性:在映射文件中的 <insert> 标签中,添加 useGeneratedKeys="true" 和 keyProperty="id" 属性。这样,当执行插入操作时,数据库生成的主键值会被自动赋值给传入参数对象的 id 属性。
  2. 使用 selectKey 标签:在映射文件中的 <insert> 标签内部,添加 <selectKey> 标签来设置主键生成策略。 <selectKey> 标签有两个重要属性: resultType 指定主键的类型,keyProperty 指定将主键赋值给哪个属性。此外,还可以通过 before 或 after 属性来设置是在插入前还是插入后获取主键值。
总的来说,通过这些配置,MyBatis可以在执行插入操作后返回主键ID,并将其赋值给对应的Java对象

6.2理解

在 MyBatis 中,可以通过以下几种方式来获取插入操作后生成的主键 ID:
  1. 使用数据库的自增主键:
    1. 如果你的表使用了数据库的自增主键(如 MySQL 的 AUTO_INCREMENT),则在执行插入操作后,可以通过 SELECT LAST_INSERT_ID() 来获取最后插入的主键 ID。
    2. 在 MyBatis 的映射文件(Mapper XML)中,可以使用 <selectKey> 元素来配置获取主键的语句,例如:
    <insert id="insertUser" parameterType="User">
      <selectKey keyProperty="id" resultType="Long" order="AFTER">
        SELECT LAST_INSERT_ID()
      </selectKey>
      INSERT INTO user (username, password) VALUES (#{username}, #{password})
    </insert>
    1. 在执行插入操作后,MyBatis 会自动执行 <selectKey> 中配置的语句,并将获取到的主键值设置到对应的属性( keyProperty )中。
  2. 使用数据库的序列(Sequence):
    1. 如果你的表使用了数据库的序列(如 Oracle 的序列),则可以通过调用序列的NEXTVAL 函数来获取下一个序列值作为主键 ID。
    2. 在 MyBatis 的映射文件中,可以使用 <selectKey> 元素来配置获取序列值的语句,例如:
    <insert id="insertUser" parameterType="User">
      <selectKey keyProperty="id" resultType="Long" order="BEFORE">
        SELECT user_seq.NEXTVAL FROM DUAL
      </selectKey>
      INSERT INTO user (id, username, password) VALUES (#{id}, #{username}, #
      {password})
    </insert>
    1. 在执行插入操作前,MyBatis 会先执行 <selectKey> 中配置的语句,并将获取到的序列值设置到对应的属性( keyProperty )中。
  3. 使用数据库的触发器(Trigger):
    1. 如果你的表使用了数据库的触发器,在触发器中可以获取插入操作后生成的主键 ID,并将其设置到对应的列中。
    2. 在 MyBatis 中,执行插入操作后,可以通过查询插入的记录来获取主键 ID,例如:
    // 执行插入操作
    sqlSession.insert("insertUser", user);
    // 获取插入后的主键 ID
    Long id = user.getId();
    1. 根据你所使用的数据库和表的配置,选择适合的方式来获取插入操作后的主键 ID。

7简述 Mybatis 的插件运行原理,如何编写一个插件

7.1背记

MyBatis 插件的运行原理基于Java的动态代理机制。Mybatis 只支持针对 ParameterHandler、ResultSetHandler、StatementHandler、Executor 这4 种接口的插件, Mybatis 使用 JDK 的动态代理, 为需要拦截的接口生成代理对象以实现接口方法拦截功能, 每当执行这 4 种接口对象的方法时,就会进入拦截方法,具体就是 InvocationHandler 的invoke() 方法, 拦截那些你指定需要拦截的方法。

7.2理解

MyBatis自定义插件的实现方式主要包括以下几个步骤:
  1. 创建插件类:首先,需要创建一个Java类来表示自定义插件。这个类需要实现MyBatis提供的 Interceptor 接口,并重写其中的 intercept() 方法。在这个方法中,可以编写自定义的拦截逻辑。
  2. 配置插件:在MyBatis的全局配置文件(mybatis-config.xml)中,通过 <plugins> 标签定义和加载插件。在 <plugins> 标签内部,使用 <plugin> 标签指定自定义插件的全限定类名。
  3. 注册插件:在MyBatis的 Configuration 配置对象中,将实现了 Interceptor 接口的插件进行注册。这样MyBatis就能够识别并使用这些插件。
  4. 构建拦截器链:MyBatis基于责任链设计模式,将多个拦截器串联起来,形成一个拦截器链。当核心组件的方法被调用时,会依次经过每个拦截器的处理。
  5. 动态代理机制:MyBatis利用Java的动态代理技术,对 ParameterHandler 、ResultSetHandler 、 StatementHandler 和 Executor 这四种核心接口创建代理对象。当这些组件的方法被调用时,会先执行拦截器链中的代码,再执行原始方法。
  6. 插件执行:当MyBatis的核心组件执行方法时,会触发拦截器的 intercept() 方法。在这个方法中,可以实现对SQL语句的修改、日志打印、性能监控等功能。执行完拦截逻辑后,可以选择是否继续执行原始方法。
  7. 完成插件功能:通过上述步骤,自定义插件完成了对MyBatis功能的增强或修改。开发者可以根据需要调整插件的行为,以实现特定的业务需求。