SSM框架的学习与应用(Spring + Spring MVC + MyBatis)-Java EE企业级应用开发学习记录(第五天)MyBatis的注解开发
昨天我们深入学习了MyBatis多表之间的关联映射,了解掌握了一对一关联映射,一对多关联映射,嵌套查询方式以及嵌套结果方式,掌握了缓存机制的一级缓存,二级缓存等概念,也使用了代码进行复现理解。但是都是基于XML配置文件的方式来实现的,现在我们要学习一下Mybatis提供的更加简便的注解配置方式。
那么今天我们要掌握的是MyBatis的注解开发:
- 掌握基于注解的单表增删改查
- 掌握基于注解的关联查询
一、基于注解的单表增删改查
什么是注解?
Annotation(注解)就是Java提供了一种为程序元素关联任何信息或任何元数据(metadata)的途径和方法。Annotion(注解)是一个接口,程序可以通过反射来获取指定程序元素的Annotion对象,然后通过Annotion对象来获取注解里面的元数据。
注解不会影响程序代码的执行,Annotation能被用来为某个程序元素(类、方法、成员变量等)关联任何的信息。需要注意的是,这里存在着一个基本的规则:Annotation不能影响程序代码的执行,无论增加、删除 Annotation,代码都始终如一的执行。
什么是MyBatis的注解开发?
MyBatis 支持通过注解来进行数据库操作,这种方式被称为 MyBatis 的注解开发。通过注解可以更直观地在 Java 代码中定义 SQL 语句,省去了繁琐的 XML 配置。
MyBatis的注解开发通常需要使用接口来进行。
①在我们项目的根目录java下,新建一个dao包。
DAO(Data Access Object)层是在软件架构中用于封装与数据库或其他持久化机制的交互的一种设计模式。在典型的三层架构(或多层架构)中,DAO 层通常是位于持久化层的组成部分,它负责执行数据库操作,提供数据的增、删、改、查等基本操作,同时也可以包含一些复杂的查询逻辑它提供了一种抽象层,将应用程序的业务逻辑与底层的数据访问细节分离开来,使代码更加清晰、可维护和可测试。
②dao包中新建一个接口(interface):Bookmapper(如下图)
③BookMapper接口中编写上SQL放在方法的上方。
package dao;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import pojo.Book;
import java.util.List;
public interface BookMapper {
@Select("select * from book")
List<Book> selectBook();
@Select("select * from book where id =#{id}")
Book getOneBookById(Integer id);
@Update("update book set id=#{id},bookName=#{bookName},price=#{price},author=#{author}")
Boolean updateALlItem(Book book);
}
我们之前有学过,SQl语句,那么就很简单能够理解了,抽出一小块理解一下:
@Select("select * from book")//相当于sql语句,用于访问数据库
List<Book> selectBook();//相当于java里面的方法,返回值是List<Book>
@Select("select * from book")
: 这是一个用于查询的注解,表示执行了一个查询操作。括号中的内容是执行的SQL语句,这里查询语句的意思是查询整个book
表的所有数据。List<Book>
: 这是查询的返回类型,表示查询的结果将会被映射到一个List
集合中,集合中的每个元素都是一个Book
对象。selectBook()
: 这是方法的名称,可以根据需要命名。当调用这个方法时,MyBatis会执行对应的SQL查询,并将结果映射到返回类型指定的集合中。记得使用了注解的话,就得对应写入方法,不然会报错。
这样的注解方式可以直接在接口中定义SQL查询语句,非常方便。MyBatis会在运行时根据这些注解执行对应的数据库操作。
④往mybatis-config.xml中注册注解。
<mappers>
<mapper resource="mapper/PasswordMSMapper.xml"/>
<mapper resource="mapper/IdCardMapper.xml"/>
<mapper resource="mapper/PersonMapper.xml"/>
<mapper resource="mapper/UserMapper.xml"/>
<mapper resource="mapper/BookMapper.xml"/>
<mapper class="dao.BookMapper" />
</mappers>
注意和以前的xml不同的是,这里是class,不是resource
<mapper class="dao.BookMapper" />
是 MyBatis 配置文件中的一个元素,用于指定一个 DAO 接口对应的 Mapper 类。这个元素告诉 MyBatis 哪个接口的方法应该与 XML 映射文件中的 SQL 语句进行关联。
在这里,<mapper class="dao.BookMapper" />
的作用是将名为 BookMapper
的 DAO 接口与 XML 映射文件关联起来,使得该接口的方法可以与 XML 文件中的 SQL 语句进行匹配,从而实现数据库的操作。
⑤编写测试类查看效果
@Test
void findBookById() {
//Annotation mode test注解方式查询数据库
//1.创建SqlSession实例,用于连接数据库
SqlSession session=MyBatisUtil.createSqlSession();
//2.调用查询语句,传入参数查询
List<Book> books=session.selectList("selectBook");
//3.输出结果
for(Book book:books){
logger.info("ID:"+book.getId()+", 书名:"+book.getBookName()+",价格 :"+book.getPrice()+",作者:"+book.getAuthor());
}
session.close();//关闭连接,若是增删改这些业务操作需要先提交一下事务session.commit();
}
可以发现能够正常的调用sql语句,并且访问数据库获取结果,但是呢红色圈标注的那里,一般我们要做修改成这样:表示调用BookMapper接口中的selectBook方法,这样更符合接口的调用习惯。
//2.调用查询语句,传入参数查询
List<Book> books=session.getMapper(BookMapper.class).selectBook();
那么自行补充其他的注解语句,增删改查等,或者可以下载我的资源文件,里面全都写好了
二、掌握基于注解的关联查询
还是我们之前的场景一对一关联映射,一对多关联映射
①一对一关联映射Person和IdCard,先编写俩个类的Mapper接口文件,因为pojo类之前已经生成过了,前面几天中就用过了。
PersonMapper接口如下:
package dao;
import org.apache.ibatis.annotations.*;
import pojo.IdCard;
import pojo.Person;
@Mapper
public interface PersonMapper {
// 根据id查询人员信息,并关联查询身份证信息
@Select("SELECT * FROM person WHERE id = #{id}")
@Results({
@Result(property = "id", column = "id"),
@Result(property = "name", column = "name"),
@Result(property = "age", column = "age"),
@Result(property = "sex", column = "sex"),
@Result(property = "cardId", column = "id", javaType = IdCard.class, one = @One(select = "dao.IdCardMapper.getIdCardById"))
})//这里就是经典的一对一关联映射了 javaType也是一对一映射才使用的,One也是,
Person getPersonWithIdCard(Integer id);
// 插入人员信息
@Insert("INSERT INTO person (name, age, sex, card_id) VALUES (#{name}, #{age}, #{sex}, #{cardId.id})")
@Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
void insertPerson(Person person);
// 更新人员信息
@Update("UPDATE person SET name = #{name}, age = #{age}, sex = #{sex}, card_id = #{cardId.id} WHERE id = #{id}")
int updatePerson(Person person);
// 删除人员信息
@Delete("DELETE FROM person WHERE id = #{id}")
int deletePerson(Integer id);
}
IdCardMapper接口如下:
package dao;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import pojo.IdCard;
@Mapper
public interface IdCardMapper {
@Select("SELECT * FROM idcard WHERE id = #{id}")
IdCard getIdCardById(@Param("id") Integer id);
//插入语句
@Insert("INSERT INTO idcard (code) VALUES (#{code})")
@Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
void insertIdCard(IdCard idCard);
}
②mybatis-config.xml中写入注解注册
<mappers>
<mapper resource="mapper/PasswordMSMapper.xml"/>
<mapper resource="mapper/IdCardMapper.xml"/>
<mapper resource="mapper/PersonMapper.xml"/>
<mapper resource="mapper/UserMapper.xml"/>
<mapper resource="mapper/BookMapper.xml"/>
<mapper class="dao.BookMapper" />
<mapper class="dao.PersonMapper" />
<mapper class="dao.IdCardMapper" />
</mappers>
记得是使用class元素不是resource了
③编写测试类查看一对一关联映射查询的情况
可以看到生成了俩个sql语句去进行数据库访问,这是因为我们使用了嵌套查询的方式
查看PersonMapper中的设定:
@Result(property = "cardId", column = "id", javaType = IdCard.class, one = @One(select = "dao.IdCardMapper.getIdCardById"))
④稍微解释一下代码:
当使用 MyBatis 进行一对一关联查询时,我们需要告诉 MyBatis 如何将查询结果映射到 Java 对象中。这时我们会使用 @Result
注解来指定映射关系。
property
:表示 Java 对象中的属性,即要映射的属性名。column
:表示数据库中的列名,即查询结果中对应的列。javaType
:表示要映射到的 Java 类型,这里是IdCard.class
,表示要将查询结果映射为IdCard
类型的对象。one
:表示一对一关系,这里使用了@One
注解来指定关联查询的方法。
这段代码的作用是在执行一对一关联查询时,将查询结果中的 id
列映射到 Java 对象的 cardId
属性,并且通过 dao.IdCardMapper.getIdCardById
方法来查询与之关联的证件信息。这样,在查询 Person
信息的同时,也会查询并映射对应的 IdCard
信息。。
接下来是一对多关联映射,一对多的场景就是我们之前的俩个表User和tb_Order
①一对一关联映射Users和TbOrder,先编写俩个类的Mapper接口文件,因为pojo类之前已经生成过了,前面几天中就用过了。
UserMapper接口如下:
package dao;
import org.apache.ibatis.annotations.*;
import pojo.Users;
import pojo.TbOrder;
import java.util.List;
@Mapper
public interface UserMapper {
@Select("SELECT * FROM users WHERE uid=#{id}")
@Results({
@Result(property = "uid", column = "uid"),
@Result(property = "uname", column = "uname"),
@Result(property = "uage", column = "uage"),
@Result(property = "orderList", column = "uid", javaType = List.class, many = @Many(select = "dao.TbOrderMapper.findTheOrderByUserId"))
})
Users findTheOrderWithUserById(Integer id);
}
这里记得一对多是使用many,然后这里的javaType要改成List.class因为订单可能会有多条记录
TbOrderMapper接口如下:
package dao;
import org.apache.ibatis.annotations.Select;
import pojo.TbOrder;
import java.util.List;
public interface TbOrderMapper {
@Select("SELECT * FROM tb_order WHERE userid=#{id}")
List<TbOrder> findTheOrderByUserId(Integer id);
}
②mybatis-config.xml中写入注解注册
<mappers>
<mapper class="dao.BookMapper" />
<mapper class="dao.PersonMapper" />
<mapper class="dao.IdCardMapper" />
<mapper class="dao.UserMapper" />
<mapper class="dao.TbOrderMapper" />
<mapper resource="mapper/PasswordMSMapper.xml"/>
<mapper resource="mapper/IdCardMapper.xml"/>
<mapper resource="mapper/PersonMapper.xml"/>
<mapper resource="mapper/UserMapper.xml"/>
<mapper resource="mapper/BookMapper.xml"/>
</mappers>
这一次要稍作修改,因为mybatis-config.xml文件中的扫描方式是从上往下扫描,所以<mappers>
元素下引入UsersMapper和OrdersMapper接口的位置,必须在引入UserMapper.xml和TbOrderMapper.xml文件位置前面,否则程序将会首先读取到引入的UserMapper.xml和TbOrderMapper.xml文件,程序将有可能会报错。
③编写测试类:
//使用注解方式一对多关联查询订单信息通过id
@Test
void findTheOrderWithUserById(){
SqlSession session = MyBatisUtil.createSqlSession();
Users users=session.getMapper(dao.UserMapper.class).findTheOrderWithUserById(1);
List<TbOrder> tbOrders=users.getOrderList();
for (TbOrder order:tbOrders){
logger.info("id"+users.getUid()+",姓名:"+users.getUname()+",年龄:"+users.getUage()+",产品名:"+order.getProductname()+",价格:"+order.getPrice()+",库存"+order.getNumber());
}
session.close();
}
输出结果如下:
成功显示一对多数据查询,那么要注意的是一对一一对多的数据插入等操作,记得先对单表进行操作,再去更新有外键的表,这样才不会报错,出现误读。
以下是一些常用的 MyBatis 注解及其用法:
-
@Select:用于查询操作。
@Select("SELECT * FROM users WHERE id = #{id}") User getUserById(int id);
-
@Insert:用于插入操作。
@Insert("INSERT INTO users (id, username, email) VALUES (#{id}, #{username}, #{email})") int insertUser(User user);
-
@Update:用于更新操作。
@Update("UPDATE users SET username = #{username}, email = #{email} WHERE id = #{id}") int updateUser(User user);
-
@Delete:用于删除操作。
@Delete("DELETE FROM users WHERE id = #{id}") int deleteUser(int id);
-
@Result 和 @Results:用于定义结果映射。
@Results({ @Result(column = "id", property = "id"), @Result(column = "username", property = "username"), @Result(column = "email", property = "email") }) @Select("SELECT * FROM users") List<User> getAllUsers();
-
@Param:用于传递参数。
@Select("SELECT * FROM users WHERE username = #{username} AND email = #{email}") User getUserByUsernameAndEmail(@Param("username") String username, @Param("email") String email);
-
@Options:用于设置一些选项,如主键返回,主键自增等
@Insert("INSERT INTO users (username, email) VALUES (#{username}, #{email})") @Options(useGeneratedKeys = true, keyProperty = "id") int insertUser(User user);
-
@ResultMap:引用在 XML 配置文件中定义的 ResultMap。
@ResultMap("UserResultMap") @Select("SELECT * FROM users WHERE id = #{id}") User getUserById(int id);
使用注解开发可以更紧凑地定义数据库操作,但对于复杂的动态 SQL 或多表关联查询,通常 XML 配置更为灵活和可读。在实际项目中,你可以根据场景选择使用注解还是 XML 配置,甚至两者结合使用。
总结
今天是Mybatis学习的第五天,今天学的Mybatis的注解开发。其实需要详细理解一下,然后自己去完成一下注解方式单表的增删改,还有注解方式的多表关联查询,嵌套条件方式和嵌套结果方式。看似简单,实则需要自己动手操作才能彻底掌握,理解清楚多表之间的关系,哪个表必须先处理,然后怎么样去嵌套获取信息等。还有今天了解一些注解关键字,虽然看着熟悉,实际上使用的话,还是会有一些坑要踩的,需要慢慢理解。
想要跟着学习的可以去我的资源里面找对应的文件下载,我的md文件也会发上去,项目文件会上传可以自己跟着学习一下。
PS:还可以自己学着掌握使用Mybatis和Xml联合开发的方式,或者我后面单独放一章出来讲。
作者:Stevedash
发表于:2023年8月27日 14点40分