Java开发可离不开的@Mapper注解举例详解
作者:潜意识Java
前言
最近在学 Java 编程的时候,碰到的一个超级厉害的 “小助手”,叫 @Mapper 注解。你们知道我平时捣鼓那些项目的时候,和数据库打交道那叫一个头疼,各种复杂的操作,写得代码又臭又长。但自从我用上了 @Mapper 注解,哎呀妈呀,就像给我的编程之路开了挂,代码变得简洁明了,开发效率蹭蹭地往上涨,整个人都轻松多了。而且我跟你们说,我去实习的时候发现,还有了解行业信息的时候,那些大公司、小公司,大部分搞 Java 开发的项目里都在用这个注解,要是咱掌握了,不管是以后找工作,还是在公司里想要升职加薪,那都更有优势,就好像握住了一把开启职场大门的金钥匙,所以大家可得跟着我好好学学。
啥是 @Mapper,给家人讲明白
(一)通俗解释
咱先通俗地讲讲 @Mapper 注解是啥。你们就把它想象成一个超级快递员,咱们写的 Java 代码呢,就像是一个个寄件人和收件人,数据库呢,就是那个大仓库。这个 @Mapper 注解快递员,就在 Java 代码和数据库之间跑来跑去,传递数据。比如说,咱们要往数据库里存个新用户的信息,或者从数据库里把某个用户的资料找出来,只要给这个快递员下达指令,也就是在代码里用好 @Mapper 注解,它就能麻溜地把数据存储、查询这些事儿给办好,让咱们不用操心那些复杂的底层操作,轻松实现咱们想要的功能,是不是很神奇?
(二)专业剖析
再深入一点,从专业角度来说,@Mapper 注解在 MyBatis 框架里可是个关键角色。MyBatis 是啥呢?它是一个超好用的持久层框架,能帮咱们把 Java 程序和数据库连接得稳稳当当。而 @Mapper 注解呢,就是在这个连接过程中起重要作用。它让咱们可以通过定义接口,在接口里写各种方法,这些方法呢,又能和咱们写在 XML 文件里,或者直接用注解写的 SQL 语句一一对应起来,实现精准的数据库交互。比如说,咱们在接口里定义一个查找用户的方法,然后用 @Mapper 注解标记这个接口,再配上对应的 SQL 语句,当咱们在 Java 代码里调用这个接口方法的时候,MyBatis 就知道要去数据库里执行哪条 SQL 语句,把咱们想要的数据找回来,是不是觉得这背后的设计很精妙?
动手实操,代码搞起
(一)环境搭建准备
光说不练假把式,咱们现在就动手实操起来。第一步,得搭建开发环境,就像盖房子得先打地基一样。咱们先创建一个 Maven 项目,要是不知道 Maven 是啥,它就像是一个贴心的管家,帮咱们把项目需要的各种库文件都管得井井有条。在咱们常用的开发工具里,像 Intellij IDEA,打开之后,按照向导一步一步来,先填好项目的基本信息,比如 “Group”(一般是公司域名倒着写,咱们自己练手就随便填个,像 “com.example”)、“Artifact”(项目名,自己起个喜欢的就行,像 “demo-project”)。然后,在项目的 pom.xml 文件里,得添加 MyBatis 以及咱们要连接的数据库驱动依赖。比如说,如果咱们连接 MySQL 数据库,就得加上这些:
<dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.2.0</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.23</version> </dependency>
这里的 “org.mybatis.spring.boot:mybatis-spring-boot-starter” 就是 MyBatis 在 Spring Boot 项目里的启动器,它把 MyBatis 相关的东西都整合好了,方便咱们使用;“mysql:mysql-connector-java” 就是连接 MySQL 的驱动。把这些依赖加好,咱们的开发环境就算是搭好了,就可以开始下一步啦。
(二)定义实体类
环境搭好了,接下来咱们定义实体类。以用户信息为例,咱们在项目的 “com.example.entity” 目录下(要是没有这个目录,就新建一个),创建一个 User 实体类,代码如下:
package com.example.entity; public class User { private Long id; // 用户ID,每个用户独一无二的标识 private String name; // 用户姓名 private String email; // 用户邮箱 // 这里得生成get、set方法,方便MyBatis存取数据 public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } }
这个 User 实体类就像是一个装用户信息的小盒子,里面的属性对应着数据库里用户表的字段,通过 get、set 方法,MyBatis 就能方便地把数据取出来放进去,是不是很好理解?
(三)创建 Mapper 接口
有了实体类,咱们接着创建 Mapper 接口。在 “com.example.mapper” 目录下(同样,没有就新建),创建一个 UserMapper 接口,代码如下:
package com.example.mapper; import com.example.entity.User; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Delete; import org.apache.ibatis.annotations.Update; import org.apache.ibatis.annotations.Select; import java.util.List; @Mapper public interface UserMapper { @Insert("INSERT INTO user (name, email) VALUES (#{name}, #{email})") void insertUser(User user); @Delete("DELETE FROM user WHERE id = #{id}") void deleteUserById(Long id); @Update("UPDATE user SET name = #{name}, email = #{email} WHERE id = #{id}") void updateUser(User user); @Select("SELECT * FROM user WHERE id = #{id}") User selectUserById(Long id); @Select("SELECT * FROM user") List<User> selectAllUsers(); }
这里的 @Mapper 注解就像给这个接口贴上了一个特殊的标签,告诉 MyBatis 这个接口很重要,要重点关注。接口里的每个方法,都对应着一条 SQL 操作,像插入用户信息、删除用户、更新用户资料、根据 ID 查找用户、查找所有用户,咱们都用对应的 @Insert、@Delete、@Update、@Select 注解把 SQL 语句写在方法上,而且注意看,这些 SQL 语句里的 #{参数名},就能自动把咱们传入的 User 实体类里的对应属性值取出来,用到 SQL 语句里,是不是超级智能?
(四)编写 SQL 语句
刚才咱们在 Mapper 接口里已经写了一些简单的 SQL 语句,不过有时候,咱们的需求会更复杂一点。比如说,咱们要根据用户的姓名和邮箱模糊查询用户,这时候就可以用动态 SQL。在 UserMapper 接口里,咱们再加一个方法:
@Select("<script>" + "SELECT * FROM user " + "<where>" + "<if test='name!= null'>" + "AND name LIKE '%${name}%'" + "</if>" + "<if test='email!= null'>" + "AND email LIKE '%${email}%'" + "</if>" + "</where>" + "</script>") List<User> selectUsersByNameAndEmail(User user);
这里用了<if>标签来判断传入的用户姓名和邮箱是不是为空,如果不为空,就拼接到 SQL 语句里,实现模糊查询,是不是很灵活?而且注意,这里用的是参数名,它和参数名有点不一样,{参数名} 是直接把参数值拼接到 SQL 语句里,适合这种模糊查询的场景,不过要注意防止 SQL 注入哦,咱们后面再详细说。
(五)配置文件完善
代码写得差不多了,咱们还得完善配置文件。在 Spring Boot 项目里,一般是在 application.properties 或者 application.xml 文件里设置数据库连接信息。比如说,在 application.properties 文件里,咱们得写上这些:
spring.datasource.url=jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=UTC spring.datasource.username=root spring.datasource.password=123456 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
这里的 “spring.datasource.url” 就是数据库的连接地址,“localhost” 表示本地数据库,“3306” 是 MySQL 的默认端口,“mydb” 是数据库名,后面的参数 “useSSL=false” 是说不用 SSL 加密连接(在本地测试可以这样,正式环境可能需要根据情况调整),“serverTimezone=UTC” 是设置时区,避免时间上的一些问题;“spring.datasource.username” 和 “spring.datasource.password” 就是登录数据库的用户名和密码,这得根据咱们自己安装数据库时设置的来填;“spring.datasource.driver-class-name” 就是指定数据库驱动类,这里是 MySQL 的驱动。把这些配置写好,就像给咱们的程序指明了数据仓库的位置,它就能顺利找到数据库,开始干活啦。
(六)测试验证功能
最后,咱们得测试验证一下咱们写的代码是不是好使。咱们在项目的测试类里,比如说 “com.example.test” 目录下(没有就新建),创建一个 UserMapperTest 类,代码如下:
package com.example.test; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import com.example.entity.User; import com.example.mapper.UserMapper; import java.util.List; @SpringBootTest public class UserMapperTest { @Autowired private UserMapper userMapper; @Test public void testInsertUser() { User user = new User(); user.setName("张三"); user.setEmail("zhangsan@example.com"); userMapper.insertUser(user); } @Test public void testSelectUserById() { Long id = 1L; User user = userMapper.selectUserById(id); assert user!= null; System.out.println("用户姓名:" + user.getName() + ", 邮箱:" + user.getEmail()); } @Test public void testSelectAllUsers() { List<User> userList = userMapper.selectAllUsers(); for (User user : userList) { System.out.println("用户姓名:" + user.getName() + ", 邮箱:" + user.getEmail()); } } }
这里用了 Spring Boot 的测试框架,通过 @Autowired 注解把咱们之前写的 UserMapper 接口注入进来,然后在各个测试方法里,分别调用插入用户、根据 ID 查找用户、查找所有用户的方法,用断言来验证结果,比如说查找用户的时候,断言找到的用户不为空,这样就能确保咱们的代码能正常工作,就像考试后核对答案一样,心里踏实多了。
深入探索,高级玩法揭秘
(一)动态 SQL 语句运用
刚才咱们简单介绍了动态 SQL,现在深入讲讲。除了刚才用的<if>标签,还有<choose>、<where>等标签也很常用。比如说,咱们要实现一个复杂的查询,根据不同的条件查找用户,有时候按姓名查,有时候按邮箱查,有时候按年龄范围查,这时候就可以用<choose>标签,代码如下:
@Select("<script>" + "SELECT * FROM user " + "<where>" + "<choose>" + "<when test='name!= null'>" + "AND name LIKE '%${name}%'" + "</when>" + "<when test='email!= null'>" + "AND email LIKE '%${email}%'" + "</when>" + "<when test='age!= null'>" + "AND age BETWEEN #{age.start} AND #{age.end}" + "</when>" + "</choose>" + "</where>" + "</script>") List<User> selectUsersByCondition(User user, AgeRange age);
这里假设咱们还有一个 AgeRange 类,用来表示年龄范围,通过<choose>标签,咱们可以根据传入的不同条件,灵活地生成不同的 SQL 语句,满足各种复杂的查询需求,是不是很强大?
(二)关联查询与结果映射
再来讲讲关联查询,比如说咱们的项目里有用户表和订单表,一个用户可能有多个订单,咱们有时候需要查询用户及其订单信息,这时候就可以用 @Results、@ResultMap 注解。首先,咱们得在 UserMapper 接口里定义一个方法:
@Select("SELECT u.*, o.* FROM user u LEFT JOIN order o ON u.id = o.user_id") @Results(id = "userWithOrdersResult", value = { @Result(property = "id", column = "u.id"), @Result(property = "name", column = "u.name"), @Result(property = "email", column = "u.email"), @Result(property = "orders", javaType = List.class, many = @Many(select = "com.example.mapper.OrderMapper.selectOrdersByUserId")), }) User getUserWithOrders(Long id);
这里的 @Select 注解写了关联查询的 SQL 语句,通过 LEFT JOIN 把用户表和订单表连接起来。@Results 注解用来定义结果映射,把查询结果正确地映射到 User 实体类和它关联的订单列表上,其中 @Result 注解对应着每个属性的映射,对于订单列表,咱们用 @Result 的 many 属性,指定了一个子查询,通过调用 OrderMapper 接口的 selectOrdersByUserId 方法,获取用户的订单信息,是不是很巧妙?
常见问题排雷
(一)注解失效问题
在使用 @Mapper 注解的时候,有时候会遇到注解失效的问题。比如说,咱们明明写了 @Mapper 注解,但是 MyBatis 好像没看到一样,接口方法调用就报错。这可能是因为咱们没有正确配置 MyBatis,让它扫描到咱们的 Mapper 接口。在 Spring Boot 项目里,如果咱们用的是注解驱动的方式,得确保在启动类上加上 @MapperScan 注解,指定 Mapper 接口所在的包,比如:
package com.example; import org.springframework.boot.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.MapperScan; @SpringBootApplication @MapperScan("com.example.mapper") public class DemoApplication { public static void main(String[] args) { SpringBootApplication.run(DemoApplication.class, args); } }
这里的 @MapperScan ("com.example.mapper") 就告诉 Spring Boot,去 “com.example.mapper” 这个包下扫描所有的 Mapper 接口,这样就能解决注解失效的问题啦。
(二)SQL 语法错误排查
还有一个常见的问题就是 SQL 语法错误。咱们写 SQL 语句的时候,不小心写错了,比如说少写了个引号,或者关键字拼错了,这时候程序运行就会报错。遇到这种情况,咱们得学会从报错信息里快速定位问题。一般来说,MyBatis 会给出比较详细的报错信息,告诉咱们是哪个 SQL 语句出错了,在哪个位置,咱们根据这些信息,仔细检查 SQL 语句,就能找到错误并改正。比如说,报错信息里说 “near 'FROM user WHERE id = #{id}': syntax error”,咱们就知道是在 “FROM user WHERE id = #{id}” 这个语句里有语法错误,可能是少了个空格,或者关键字写错了,仔细一看,原来是 “DELETE” 写成了 “DELET”,改正之后就没问题啦。
总结
到此这篇关于Java中@Mapper注解举例详解的文章就介绍到这了,更多相关Java的@Mapper注解内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!