面试-基础

#哪个编程工具让你的工作效率翻倍?#

一、mybatis和mybatisplus的区别

MyBatis 和 MyBatis Plus 都是 Java 中常用的持久层框架,它们有以下一些区别:

1、功能特性

  1. 基础功能:
    • MyBatis 是一个传统的 SQL 映射框架,提供了基本的 SQL 映射、结果集映射、动态 SQL 生成等功能。
    • MyBatis Plus 在 MyBatis 的基础上进行扩展,提供了更多实用的功能,如内置通用 Mapper、代码生成器、分页插件、性能分析插件等。
  1. CRUD 操作:
    • MyBatis 需要手动编写 SQL 语句来实现各种数据库操作,包括增删改查。虽然可以使用动态 SQL 来简化一些常见的操作,但对于一些复杂的查询和操作,可能需要编写较多的 SQL 代码。
    • MyBatis Plus 提供了更加便捷的 CRUD 操作方法,例如通过继承 BaseMapper 接口,就可以直接使用内置的方法来实现单表的增删改查操作,大大减少了重复的代码编写工作。
  1. 分页功能:
    • MyBatis 本身没有内置的分页功能,需要通过第三方插件或者手动编写分页 SQL 来实现。
    • MyBatis Plus 提供了分页插件,可以方便地实现分页查询,只需要传入分页参数,即可自动生成分页 SQL 并进行查询。

2、开发效率

  1. 代码量:
    • 使用 MyBatis 进行开发时,对于一些常见的数据库操作,需要编写大量的 SQL 语句和 Java 代码来实现业务逻辑。
    • MyBatis Plus 提供了很多便捷的功能和工具,可以大大减少代码量。例如,使用代码生成器可以自动生成实体类、Mapper 接口和 XML 文件,减少了手动编写代码的工作量。
  1. 开发速度:
    • 由于 MyBatis Plus 提供了更多的便捷功能和工具,开发人员可以更快地实现业务需求,提高开发速度。
    • MyBatis 则需要开发人员手动编写更多的代码,开发速度相对较慢。

3、性能表现

  1. SQL 执行效率:
    • MyBatis 和 MyBatis Plus 在 SQL 执行效率上没有明显的差异,它们都将 SQL 语句的执行交给数据库来完成。
    • 但是,MyBatis Plus 的分页插件等功能可能会在一定程度上影响性能,因为它需要在查询结果集上进行分页处理。
  1. 内存占用:
    • MyBatis 和 MyBatis Plus 的内存占用情况也基本相同,主要取决于数据库连接池的配置和查询结果集的大小。

4、社区支持和生态

  1. 社区活跃度:
    • MyBatis 作为一个成熟的框架,拥有庞大的用户群体和活跃的社区。在遇到问题时,可以很容易地在网上找到解决方案。
    • MyBatis Plus 作为一个相对较新的框架,社区活跃度也在不断提高。它的开发者团队也在积极维护和更新框架,不断推出新的功能和改进。
  1. 生态系统:
    • MyBatis 有很多第三方插件和工具,可以与其他框架和技术进行集成。例如,可以与 Spring、Spring Boot 等框架进行无缝集成。
    • MyBatis Plus 也可以与 Spring、Spring Boot 等框架进行集成,并且它的代码生成器等工具也可以与其他工具进行配合使用,形成一个完整的开发生态系统。

二、逻辑删除

在数据库管理中,逻辑删除是一种相对温和的数据处理方式,与物理删除相对应。

1、定义与原理

逻辑删除并非真正从数据库中移除数据,而是通过设置一个特定的字段(通常称为 “删除标志位”)来标记数据为已删除状态。当进行查询操作时,可以通过过滤这个标志位来决定是否显示该数据。例如,设置一个名为 “is_deleted” 的字段,值为 0 表示未删除,值为 1 表示已删除。

2、优点

  1. 数据可恢复性高
    • 与物理删除不同,逻辑删除只是对数据进行了标记,实际数据仍然存在于数据库中。如果出现误删情况或者需要恢复历史数据,只需要修改删除标志位即可,大大提高了数据的可恢复性。
    • 比如在一个电商系统中,用户不小心删除了订单记录,但如果采用逻辑删除,管理员可以在需要的时候轻松恢复这些订单数据,避免了因误操作带来的严重后果。
  1. 数据完整性保留
    • 在一些复杂的业务场景中,数据之间可能存在关联关系。如果进行物理删除,可能会破坏数据的完整性。而逻辑删除可以保持数据的关联关系,确保数据库的整体结构不受影响。
    • 例如在一个企业管理系统中,员工信息可能与多个业务模块相关联。如果直接物理删除员工数据,可能会导致其他模块的数据出现错误或不完整。采用逻辑删除则可以避免这种情况的发生。
  1. 审计与历史记录
    • 逻辑删除可以方便地进行数据审计和历史记录查询。通过保留已删除数据的状态,可以追踪数据的变化过程,了解数据何时被删除以及删除的原因。
    • 对于一些对数据安全性和合规性要求较高的行业,如金融、医疗等,逻辑删除可以满足审计和监管的要求。

3、实现方式

  1. 数据库层面
    • 在数据库表设计中,添加一个表示删除状态的字段。在进行删除操作时,更新该字段的值而不是真正删除数据行。
    • 可以使用数据库的触发器来自动维护删除标志位,确保数据的一致性。
  1. 应用程序层面
    • 在应用程序的业务逻辑中,处理删除操作时,调用数据库的更新语句来设置删除标志位。
    • 在查询数据时,根据删除标志位进行过滤,只返回未删除的数据。

4、注意事项

  1. 数据清理
    • 虽然逻辑删除可以保留数据,但随着时间的推移,数据库中可能会积累大量已删除的数据,占用存储空间。因此,需要定期对已删除的数据进行清理,以保持数据库的性能。
    • 可以制定数据清理策略,例如在一定时间后将真正不再需要的数据进行物理删除。
  1. 查询性能
    • 由于查询时需要过滤删除标志位,可能会对查询性能产生一定的影响。特别是在数据量较大的情况下,需要优化查询语句和数据库索引,以提高查询效率。
    • 可以根据实际业务需求,合理设计索引,确保查询性能不受影响。

三、简单地增删改查

在软件开发中,简单的增删改查(CRUD)操作是非常基础且频繁使用的功能。以下分别介绍增删改查的基本概念和一般实现方式。

1、增加(Create)

  1. 定义:向数据库中插入新的数据记录。
  2. 实现方式:
    • 在应用程序中,通常通过表单或其他输入方式收集用户输入的数据。
    • 然后,将这些数据组装成数据库可以接受的格式,并使用数据库插入语句(如 SQL 的 INSERT 语句)将数据插入到相应的表中。
    • 例如,在一个学生管理系统中,要添加一个新的学生记录,可以在界面上输入学生的姓名、年龄、班级等信息,然后通过后端代码将这些信息插入到学生表中。

2、删除(Delete)

  1. 定义:从数据库中移除指定的数据记录。
  2. 实现方式:
    • 一般是根据特定的条件来确定要删除的记录。
    • 可以通过记录的唯一标识符(如 ID)或者其他特定的属性值来定位要删除的记录。
    • 使用数据库删除语句(如 SQL 的 DELETE 语句)进行删除操作。
    • 例如,在一个订单管理系统中,如果要删除一个特定的订单,可以根据订单的 ID 来执行删除操作。

3、修改(Update)

  1. 定义:更新数据库中已有的数据记录。
  2. 实现方式:
    • 首先确定要修改的记录,可以通过与删除操作类似的方式进行定位。
    • 然后收集用户输入的新数据,将这些新数据与要修改的记录进行关联。
    • 使用数据库更新语句(如 SQL 的 UPDATE 语句)将新数据更新到数据库中。
    • 例如,在一个员工信息管理系统中,如果要修改某个员工的工资信息,可以先找到该员工的记录,然后输入新的工资值,最后将新工资值更新到数据库中。

4、查询(Retrieve)

  1. 定义:从数据库中获取满足特定条件的数据记录。
  2. 实现方式:
    • 使用数据库查询语句(如 SQL 的 SELECT 语句)来指定查询条件。
    • 查询条件可以是单个属性的值,也可以是多个属性的组合条件。
    • 查询结果可以是单个记录,也可以是多个记录的集合。
    • 例如,在一个图书管理系统中,可以根据图书的名称、作者、分类等条件进行查询,获取符合条件的图书记录。

四、多租户的处理

在软件系统中,多租户是一种架构模式,允许多个租户(客户或用户组织)共享同一套软件实例,同时保持数据的隔离和安全性。以下是多租户的常见处理方式:

1、数据库层面

  1. 独立数据库模式:
    • 为每个租户提供一个独立的数据库。这种方式可以实现最高级别的数据隔离,但成本较高,因为需要管理多个数据库实例。
    • 优点是每个租户的数据完全独立,不会受到其他租户的影响,安全性高。如果一个租户的数据出现问题,不会影响其他租户。
    • 缺点是管理复杂,需要更多的资源,并且在扩展时可能会面临一些挑战。
  1. 共享数据库、独立模式:
    • 多个租户共享同一个数据库,但每个租户有自己独立的模式(表结构)。这种方式在一定程度上降低了成本,同时也能提供较好的数据隔离。
    • 优点是可以在一定程度上减少数据库实例的数量,管理相对简单一些。每个租户的数据在逻辑上是独立的,通过不同的表结构进行区分。
    • 缺点是如果需要对数据库结构进行更改,可能会影响到所有租户。
  1. 共享数据库、共享模式:
    • 所有租户共享同一个数据库和相同的表结构。通过在表中添加一个租户标识符字段来区分不同租户的数据。
    • 优点是成本最低,管理最简单。只需要维护一个数据库实例,并且可以方便地进行数据库的扩展和维护。
    • 缺点是数据隔离性相对较弱。如果数据库出现问题,可能会影响到所有租户。同时,在进行数据查询和处理时,需要根据租户标识符进行过滤,可能会影响性能。

2、应用程序层面

  1. 租户识别:
    • 在应用程序中,需要能够识别当前请求来自哪个租户。可以通过多种方式实现,如在请求中包含租户标识符、使用会话信息、基于用户登录信息等。
    • 一旦确定了租户,应用程序就可以根据租户的需求进行相应的处理,如访问特定的数据库、加载特定的配置等。
  1. 数据过滤:
    • 在进行数据查询和处理时,应用程序需要根据租户标识符对数据进行过滤,确保只返回当前租户的数据。
    • 可以在数据库查询语句中添加租户标识符作为过滤条件,或者在应用程序代码中进行数据过滤。
  1. 配置管理:
    • 不同的租户可能有不同的配置需求,如界面显示、业务规则等。应用程序需要能够根据租户的配置进行相应的调整。
    • 可以使用配置文件、数据库表或者其他方式来存储租户的配置信息,并在应用程序启动时加载相应的配置。

3、安全考虑

  1. 数据隔离:
    • 确保不同租户的数据不能被其他租户访问。可以通过数据库层面的隔离机制和应用程序层面的数据过滤来实现。
    • 对于敏感数据,还可以采用加密等方式来进一步提高安全性。
  1. 访问控制:
    • 对租户的访问进行严格的控制,确保只有授权的用户才能访问相应的租户数据。
    • 可以使用身份验证和授权机制,如用户登录、角色权限管理等。
  1. 审计和监控:
    • 对租户的操作进行审计和监控,以便及时发现和处理安全问题。
    • 可以记录租户的操作日志,定期进行安全审计,确保系统的安全性和合规性。

五、lambadaquery构建表达式

在 Java 中,LambdaQuery 通常用于构建数据库查询的表达式,它提供了一种简洁、类型安全的方式来构建复杂的查询条件。以下是关于使用 LambdaQuery 构建表达式的介绍:

1、基本用法

  1. 引入依赖:
    • 首先,确保你的项目中引入了相应的数据库操作框架,如 MyBatis-Plus。
  1. 创建查询对象:
    • 通过数据库操作对象(如 BaseMapper)获取 LambdaQuery 对象。例如:

LambdaQuery<User> query = userMapper.lambdaQuery();

  1. 构建查询条件:
    • 使用 Lambda 表达式来指定查询条件。例如,查询年龄大于 18 岁的用户:

query.gt(User::getAge, 18);

  • 这里,User::getAge是一个方法引用,表示获取 User 对象的 age 属性,gt方法表示大于条件。

2、常见的查询操作

  1. 相等条件:
    • 使用eq方法表示相等条件。例如,查询用户名等于 “张三” 的用户:

query.eq(User::getUsername, "张三");

  1. 范围查询:
    • 使用between方法进行范围查询。例如,查询年龄在 20 到 30 岁之间的用户:

query.between(User::getAge, 20, 30);

  1. 模糊查询:
    • 使用like方法进行模糊查询。例如,查询用户名中包含 “张” 字的用户:

query.like(User::getUsername, "张");

  1. 排序:
    • 使用orderByAsc和orderByDesc方法进行升序和降序排序。例如,按照年龄升序排序:

query.orderByAsc(User::getAge);

3、复杂查询条件组合

  1. 逻辑与(and):
    • 可以连续调用多个条件方法来实现逻辑与。例如,查询年龄大于 18 岁且用户名等于 “张三” 的用户:

query.gt(User::getAge, 18).eq(User::getUsername, "张三");

  1. 逻辑或(or):
    • 使用or方法实现逻辑或。例如,查询年龄大于 18 岁或者用户名等于 “张三” 的用户:

query.gt(User::getAge, 18).or().eq(User::getUsername, "张三");

4、分页查询

  1. 设置分页参数:
    • 使用page方法设置分页参数。例如,查询第一页,每页显示 10 条数据:

Page<User> page = new Page<>(1, 10); query.page(page);

  1. 获取分页结果:
    • 执行查询后,返回的是一个包含分页结果的 Page 对象。可以从 Page 对象中获取查询结果和分页信息。例如:

Page<User> resultPage = query.page(page); List<User> userList = resultPage.getRecords(); long total = resultPage.getTotal();

总之,LambdaQuery 提供了一种强大而灵活的方式来构建数据库查询表达式,可以根据具体的业务需求组合各种查询条件,实现复杂的数据库查询操作。

六、$和#的区别

在 MyBatis 中,

$和#都用于在 SQL 语句中引用参数,但它们有以下区别:

1、语法和使用场景

  1. #的使用:
    • 通常用于引用参数的值,并将其安全地插入到 SQL 语句中。MyBatis 会对使用#引用的参数进行预处理,以防止 SQL 注入攻击。
    • 例如:

SELECT * FROM user WHERE id = #{id}

  • 在这个例子中,#{id}会被 MyBatis 替换为实际的参数值,并且会进行适当的转义处理,确保参数值不会破坏 SQL 语句的结构或导致安全问题。
  1. $的使用:
    • 用于直接将参数值插入到 SQL 语句中,不会进行任何预处理。
    • 例如:

SELECT * FROM user WHERE id = ${id}

  • 在这个例子中,${id}会被直接替换为参数值,不会进行转义处理。如果参数值来自不可信的来源,可能会导致 SQL 注入攻击。

2、安全性

  1. #的安全性:
    • 由于 MyBatis 会对使用#引用的参数进行预处理,所以它可以有效地防止 SQL 注入攻击。这使得#在大多数情况下是更安全的选择。
    • 例如,如果用户输入的参数值包含 SQL 关键字或特殊字符,MyBatis 会对其进行转义,确保 SQL 语句的安全性。
  1. $的安全性:
    • 使用$引用参数值时,不会进行任何预处理,因此如果参数值来自不可信的来源,可能会导致 SQL 注入攻击。
    • 例如,如果用户输入的参数值包含 SQL 关键字或特殊字符,并且直接使用$插入到 SQL 语句中,可能会导致 SQL 语句被恶意篡改,从而引发安全问题。

3、灵活性

  1. #的灵活性:
    • 在某些情况下,#的灵活性可能会受到一些限制。例如,在使用数据库函数或表名、列名等标识符时,不能直接使用#引用参数值。
    • 例如,如果要根据动态的表名进行查询,不能使用#{tableName},而需要使用其他方式来实现动态 SQL。
  1. $的灵活性:
    • $在某些情况下可以提供更高的灵活性。例如,可以直接使用$引用参数值来构建动态的表名、列名或 SQL 函数参数。
    • 例如:

SELECT * FROM ${tableName} WHERE id = ${id}

  • 在这个例子中,可以通过动态设置tableName和id参数值来实现对不同表的查询。

4、性能

  1. #的性能:
    • 由于 MyBatis 会对使用#引用的参数进行预处理,可能会在一定程度上影响性能。特别是在处理大量参数或复杂的 SQL 语句时,预处理可能会增加一些开销。
    • 然而,在大多数情况下,这种性能影响是可以忽略不计的,并且为了保证安全性,这种开销是值得的。
  1. $的性能:
    • 使用$引用参数值时,不会进行预处理,因此在性能上可能会稍微优于#。但是,由于存在安全风险,不建议在需要保证安全性的情况下使用$。

七、如何实现一对多、多对一的查询

在数据库设计和查询中,一对多和多对一关系是常见的关联关系。以下分别介绍如何在 MyBatis 中实现一对多和多对一的查询。

1、一对多查询

假设我们有两个实体类,

Parent(父类)和

Child(子类),一个父类可以有多个子类。

  1. 数据库表设计:
    • 创建两个表,分别对应Parent和Child实体。例如,可以有parent_table和child_table。
    • 在child_table中设置一个外键字段,关联到parent_table的主键。
  1. 实体类设计:
    • Parent实体类中包含一个List类型的属性,用于存储关联的子对象。
    • Child实体类中包含一个Parent类型的属性,用于存储关联的父对象。
  1. MyBatis 映射文件配置:
    • 在Parent的映射文件中,使用标签来配置一对多关系的查询。
    • 例如:

<resultMap id="parentResultMap" type="Parent"> <id property="id" column="parent_id"/> <result property="name" column="parent_name"/> <collection property="children" ofType="Child" select="selectChildrenByParentId"/> </resultMap> <select id="selectParentById" resultMap="parentResultMap"> SELECT * FROM parent_table WHERE id = #{id} </select> <select id="selectChildrenByParentId" resultType="Child"> SELECT * FROM child_table WHERE parent_id = #{parentId} </select>

  • 在这个例子中,首先查询父对象,然后通过标签中的select属性指定一个子查询来获取关联的子对象。
  1. 在代码中调用:
    • 使用 MyBatis 的SqlSession或Mapper接口来调用查询方法。
    • 例如:

SqlSession sqlSession = sqlSessionFactory.openSession(); ParentMapper parentMapper = sqlSession.getMapper(ParentMapper.class); Parent parent = parentMapper.selectParentById(parentId); sqlSession.close();

2、多对一查询

假设我们有两个实体类,

Student(学生)和

School(学校),多个学生属于一个学校。

  1. 数据库表设计:
    • 创建两个表,分别对应Student和School实体。例如,可以有student_table和school_table。
    • 在student_table中设置一个外键字段,关联到school_table的主键。
  1. 实体类设计:
    • Student实体类中包含一个School类型的属性,用于存储关联的学校对象。
    • School实体类中可以不包含对学生的直接引用。
  1. MyBatis 映射文件配置:
    • 在Student的映射文件中,使用标签来配置多对一关系的查询。
    • 例如:

<resultMap id="studentResultMap" type="Student"> <id property="id" column="student_id"/> <result property="name" column="student_name"/> <association property="school" javaType="School" select="selectSchoolById"/> </resultMap> <select id="selectStudentById" resultMap="studentResultMap"> SELECT * FROM student_table WHERE id = #{id} </select> <select id="selectSchoolById" resultType="School"> SELECT * FROM school_table WHERE id = #{schoolId} </select>

  • 在这个例子中,首先查询学生对象,然后通过标签中的select属性指定一个子查询来获取关联的学校对象。
  1. 在代码中调用:
    • 使用 MyBatis 的SqlSession或Mapper接口来调用查询方法。
    • 例如:

SqlSession sqlSession = sqlSessionFactory.openSession(); StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class); Student student = studentMapper.selectStudentById(studentId); sqlSession.close();

八、怎么设置一级二级缓存

在 MyBatis 中,一级缓存和二级缓存可以提高数据查询的性能。以下是关于如何设置一级和二级缓存的方法:

1、一级缓存

  1. 概述:
    • MyBatis 的一级缓存是 SqlSession 级别的缓存,也称为本地缓存。它在同一个 SqlSession 中对相同的查询语句和参数进行缓存,避免重复执行数据库查询。
  1. 设置方式:
    • 一级缓存是默认开启的,无需进行特殊的配置。只要在同一个 SqlSession 中执行相同的查询语句,MyBatis 会自动使用一级缓存。
  1. 注意事项:
    • 当 SqlSession 执行了任何 DML(数据操作语言,如插入、更新、删除)操作时,会清空一级缓存,以确保数据的一致性。
    • 不同的 SqlSession 之间的一级缓存是相互独立的。

2、二级缓存

  1. 概述:
    • MyBatis 的二级缓存是 Mapper 级别的缓存,可以在多个 SqlSession 之间共享。它可以缓存不同 SqlSession 对同一个 Mapper 中的查询结果,提高查询性能。
  1. 设置方式:
    • 在 MyBatis 的配置文件(通常是mybatis-config.xml)中,需要开启二级缓存:

<configuration> <!-- 开启二级缓存 --> <settings> <setting name="cacheEnabled" value="true"/> </settings> <!-- 其他配置 --> </configuration>

  • 在 Mapper XML 文件中,对需要使用二级缓存的 Mapper 进行配置:

<mapper namespace="com.example.mapper.UserMapper"> <!-- 开启当前 Mapper 的二级缓存 --> <cache/> <!-- SQL 查询语句和其他配置 --> </mapper>

  • 实体类需要实现Serializable接口,以便在缓存中存储和读取:

public class User implements Serializable { // 实体类的属性和方法 }

  1. 注意事项:
    • 二级缓存的使用需要谨慎,因为它可能会导致数据不一致的问题。如果在多个 SqlSession 中同时对同一个数据进行修改,二级缓存中的数据可能会过时。
    • 可以通过设置缓存的刷新间隔、大小等参数来优化二级缓存的性能。例如:

<cache eviction="LRU" flushInterval="60000" size="1024" readOnly="true"/>

  • 这里,eviction表示缓存的清除策略(如 LRU 最近最少使用),flushInterval表示缓存的刷新间隔(单位为毫秒),size表示缓存的大小,readOnly表示缓存是否只读。

九、如何封装返回结果

在使用 MyBatis 或类似框架进行开发时,封装返回结果可以提高代码的可维护性和可读性。以下是一些常见的方法来封装返回结果:

1、自定义响应类

  1. 创建响应类:
    • 定义一个专门的响应类,用于封装查询结果或操作结果。这个类可以包含状态码、消息、数据等字段。
    • 例如:

public class Result<T> { private int code; private String message; private T data; // 构造函数、getter 和 setter 方法 }

  1. 返回封装后的结果:
    • 在业务逻辑方法中,根据操作结果设置响应类的状态码、消息和数据,并返回这个封装后的结果。
    • 例如:

public Result<User> getUserById(int id) { try { User user = userMapper.getUserById(id); return new Result<>(200, "查询成功", user); } catch (Exception e) { return new Result<>(500, "查询失败:" + e.getMessage(), null); } }

2、使用通用工具类

  1. 创建工具类:
    • 可以创建一个通用的工具类,用于封装返回结果。这个工具类可以提供一些静态方法,方便在不同的地方调用。
    • 例如:

public class ResultUtil { public static <T> Result<T> success(T data) { return new Result<>(200, "操作成功", data); } public static <T> Result<T> error(int code, String message) { return new Result<>(code, message, null); } }

  1. 返回封装后的结果:
    • 在业务逻辑方法中,使用工具类的方法来返回封装后的结果。
    • 例如:

public Result<User> getUserById(int id) { try { User user = userMapper.getUserById(id); return ResultUtil.success(user); } catch (Exception e) { return ResultUtil.error(500, "查询失败:" + e.getMessage()); } }

3、结合异常处理

  1. 定义自定义异常:
    • 可以定义一些自定义的异常类,用于表示特定的业务错误或异常情况。
    • 例如:

public class BusinessException extends RuntimeException { private int code; private String message; // 构造函数、getter 和 setter 方法 }

  1. 在业务逻辑中抛出异常:
    • 当出现业务错误或异常情况时,抛出自定义异常,并设置相应的状态码和消息。
    • 例如:

public Result<User> getUserById(int id) { try { User user = userMapper.getUserById(id); return new Result<>(200, "查询成功", user); } catch (BusinessException e) { return new Result<>(e.getCode(), e.getMessage(), null); } catch (Exception e) { return new Result<>(500, "查询失败:" + e.getMessage(), null); } }

  1. 全局异常处理:
    • 可以使用全局异常处理机制,捕获自定义异常和其他未处理的异常,并返回相应的封装结果。
    • 例如,在 Spring Boot 中,可以使用@ControllerAdvice注解来定义全局异常处理类:

@ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(BusinessException.class) public Result handleBusinessException(BusinessException e) { return new Result<>(e.getCode(), e.getMessage(), null); } @ExceptionHandler(Exception.class) public Result handleException(Exception e) { return new Result<>(500, "系统错误:" + e.getMessage(), null); } }

十、如何返回自增主键

在 MyBatis 中,可以通过以下几种方式返回自增主键:

一、使用useGeneratedKeys和keyProperty属性

  1. 在 MyBatis 的 Mapper XML 文件中,对于插入语句,可以使用useGeneratedKeys="true"和keyProperty属性来指示 MyBatis 返回自增主键。
    • 例如:

<insert id="insertUser" useGeneratedKeys="true" keyProperty="id"> INSERT INTO user (name, age) VALUES (#{name}, #{age}) </insert>

  • 在这个例子中,useGeneratedKeys="true"表示使用数据库生成的主键,keyProperty="id"指定将自增主键赋值给实体类中的id属性。
  1. 在 Java 代码中调用插入方法后,可以直接从插入的对象中获取自增主键的值。
    • 例如:

User user = new User(); user.setName("张三"); user.setAge(20); userMapper.insertUser(user); int id = user.getId(); // 获取自增主键的值

二、使用selectKey标签

  1. 在 Mapper XML 文件中,对于插入语句,可以使用标签来获取自增主键的值。
    • 例如:

<insert id="insertUser"> <selectKey keyProperty="id" resultType="int" order="AFTER"> SELECT LAST_INSERT_ID() </selectKey> INSERT INTO user (name, age) VALUES (#{name}, #{age}) </insert>

  • 在这个例子中,标签的keyProperty属性指定将自增主键赋值给实体类中的id属性,resultType属性指定返回值的类型,order="AFTER"表示在插入语句执行后获取自增主键的值。SELECT LAST_INSERT_ID()是 MySQL 数据库中获取最后插入的自增主键值的方法,不同的数据库可能有不同的获取自增主键值的方法。
  1. 在 Java 代码中调用插入方法后,可以直接从插入的对象中获取自增主键的值。
    • 例如:

User user = new User(); user.setName("张三"); user.setAge(20); userMapper.insertUser(user); int id = user.getId(); // 获取自增主键的值

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值