MyBatis 注解方式就是将 SQL 语句直接写在DAO层的接口上。
在黑马2018年录制的双元视频课:\08 SSM整合案例【企业权限管理系统】\07.订单操作 有使用mybatis注解进行多表关联查询的案例,在下文会有使用注解的补充说明。
这种方式的优点是 , 对于需求比较简单的系统,效率较高。缺点是 ,当 SQL 有变化时都需要重新编译代码, 一般情况下不建议使用MyBatis的注解方式 。
因此, (原书)本章不会进行深入讲解。 在 MyBatis 注解 SQL 中,最基本的就是@Select 、@Insert 、@Update 和@Delete 四种 。 下面以 RoleMapper 为例,对这几个注解的用法进行讲解 。
-- ---------------------------- -- Table structure for sys_role -- ---------------------------- DROP TABLE IF EXISTS `sys_role`; CREATE TABLE `sys_role` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT ‘角色ID‘, `role_name` varchar(50) DEFAULT NULL COMMENT ‘角色名‘, `enabled` int(11) DEFAULT NULL COMMENT ‘有效标志‘, `create_by` bigint(20) DEFAULT NULL COMMENT ‘创建人‘, `create_time` datetime DEFAULT NULL COMMENT ‘创建时间‘, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COMMENT=‘角色表‘; -- ---------------------------- -- Records of sys_role -- ---------------------------- INSERT INTO `sys_role` VALUES (‘1‘, ‘管理员‘, ‘1‘, ‘1‘, ‘2016-04-01 17:02:14‘); INSERT INTO `sys_role` VALUES (‘2‘, ‘普通用户‘, ‘1‘, ‘1‘, ‘2016-04-01 17:02:34‘);pom.xml
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <java.version>1.8</java.version> </properties> <build> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>${java.version}</source> <target>${java.version}</target> </configuration> </plugin> </plugins> </build>
3.1 @Select 注解
在 cn.bjut.example.mapper.RoleMapper 接口中添加如下注解方法 。
package cn.bjut.example.mapper; import cn.bjut.example.model.SysRole; import org.apache.ibatis.annotations.Select; public interface RoleMapper { @Select({"select id,role_name roleName, enabled, create_by createBy, create_time createTime from sys_role where id = #{id}"}) SysRole selectById(Long id); }
使用注解方式同样需要考虑表字段和 Java 属性字段映射的问题,在第 2 章 中己经讲过 XML方式是如何实现宇段映射的,接下来看一下注解方式是如何实现的 。第一种是通过 SQL 语句使用别名来实现,上面的例子中已经使用过 。 除此之外还有另外两种方式分别是:
- 使用mapUnderscoreToCamelCase 配置
- 以及使用 resultMap 方式,下面详细说明 。
3.1.1 使用 mapUnderscoreToCamelCase 配置
在数据库中,由于大多数数据库设置不区分大小写 ,因此下画线方式的命名很常见,如 user_name 、 user_email 。在 Java 中, 一般都使用驼峰式命名,如 userName 、 userEmail 。
因为数据库和 Java 中的这两种命名方式很常见,因此 MyBatis 还提供 了 一个全局属性
mapUnderscoreToCamelCase ,通过配置这个属性为 true 可以自动将以下画线方式命名的
数据库列映射到 Java对象的驼峰式命名属性中。这个属性默认为 false ,如果想要使用该功能,
需要在 MyBatis 的配置文件(第 l 章中 的 mybatis-config.xml 文件)中增加如下配置。
<settings> <!-- 其他mybatis配置 --> <setting name=" mapUnderscoreToCamelCase" value="true"/> </settings>
使用这种配置方式不需要手动指定别名 , MyBatis 字段按照 “下画线转驼峰”的方式 自动
映射,@Select 注解中的 SQL 可以写成如下这种方式。
@Select("select id,role_name, enabled, create_by, create_time from sys_role where id = #{id}") SysRole selectById2(Long id);
3.1.2 使用resultMap方式
XML中的 resultMap 元素有一个对应的 Java 注解@Results ,使用这个注解来实现属性
映射,新增一个 selectById2 方法,代码如下 。
@Results(id = "roleResultMap", value = { @Result(property = "id", column = "id", id = true), @Result(property = "roleName", column = "role_name"), @Result(property = "enabled", column = "enabled"), @Result(property = "createBy", column = "create_by"), @Result(property = "createTime", column = "create_time") }) @Select("select id,role_name, enabled, create_by, create_time from sys_role where id = #{id}") SysRole selectById2(Long id);
从MyBatis 3.3.1版本开始,@Results注解增加了一个id属性,设置了id属性后,就可以通过id属性引用同一个@Results配置了,
示例代码如上:
如何引用这个@Results呢?新增一个 selectAll方法,代码如下。
@ResultMap("roleResultMap") @Select("select * from sys_role") List<SysRole> selectAll();
注意: 使用@ResultMap注解引用即可,当配合着使用XML配置方式的时候,还可以是XML中 <resultMap>元素的id属性值。
在RoleMapperTest 中写出以上示例方法的测试方法。
BaseMapperTest.java
/** * 基础测试类 */ public class BaseMapperTest { private static SqlSessionFactory sqlSessionFactory; @BeforeClass public static void init(){ try { Reader reader = Resources.getResourceAsReader("mybatis-config.xml"); sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); reader.close(); } catch (IOException ignore) { ignore.printStackTrace(); } } public SqlSession getSqlSession(){ return sqlSessionFactory.openSession(); } }
testSelectById、testSelectById2、testSelectAll
方法的测试代码如下:
public class RoleMapperTest extends BaseMapperTest { @Test public void testSelectById(){ //获取 sqlSession SqlSession sqlSession = getSqlSession(); try { //获取 RoleMapper 接口 RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class); //调用 selectById 方法,查询 id = 1 的角色 SysRole role = roleMapper.selectById(1l); //role 不为空 Assert.assertNotNull(role); //roleName = 管理员 Assert.assertEquals("管理员", role.getRoleName()); } finally { //不要忘记关闭 sqlSession sqlSession.close(); } } @Test public void testSelectById2(){ //获取 sqlSession SqlSession sqlSession = getSqlSession(); try { //获取 RoleMapper 接口 RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class); //调用 selectById 方法,查询 id = 1 的角色 SysRole role = roleMapper.selectById2(1l); //role 不为空 Assert.assertNotNull(role); //roleName = 管理员 Assert.assertEquals("管理员", role.getRoleName()); } finally { //不要忘记关闭 sqlSession sqlSession.close(); } } @Test public void testSelectAll(){ SqlSession sqlSession = getSqlSession(); try { RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class); //调用 selectAll 方法查询所有角色 List<SysRole> roleList = roleMapper.selectAll(); //结果不为空 Assert.assertNotNull(roleList); //角色数量大于 0 个 Assert.assertTrue(roleList.size() > 0); //验证下划线字段是否映射成功 Assert.assertNotNull(roleList.get(0).getRoleName()); } finally { //不要忘记关闭 sqlSession sqlSession.close(); } } }
3.2 @Insert注解
@Insert 注解本身是简单的,但如果需要返回主键的值,情况会变得稍微复杂一些。
3.2.1 不需要返回主键
这个方法和XML中的SQL完全一样,这里不做特别介绍,代码如下。
@Insert({"insert into sys_role(id, role_name, enabled, create_by, create_time)", "values(#{id}, #{roleName}, #{enabled}, #{createBy}, #{createTime, jdbcType=TIMESTAMP})"}) int insert(SysRole sysRole);
3.2.2 返回自增主键
新增 insert2方法,代码如下。
@Insert({"insert into sys_role(role_name, enabled, create_by, create_time)", "values(#{roleName}, #{enabled}, #{createBy}, #{createTime, jdbcType=TIMESTAMP})"}) @Options(useGeneratedKeys = true, keyProperty = "id") int insert2(SysRole sysRole);
和上面的insert方法相比,insert2方法中的SQL中少了 id一列,注解多了一个
@Options ,我们在这个注解中设置了 useGeneratedKeys 和 keyProperty 属性,用法和XML相同,
当需要配置多个列时,这个注解也提供了 keyColumn 属性,可以像XML中那样配置使用。
3.2.3 返回非自增主键
新增 insert3 方法,代码如下。
@Insert({"insert into sys_role(role_name, enabled, create_by, create_time)", "values(#{roleName}, #{enabled}, #{createBy}, #{createTime, jdbcType=TIMESTAMP})"}) @SelectKey(statement = "SELECT LAST_INSERT_ID()", keyProperty = "id", resultType = Long.class, before = false) int insert3(SysRole sysRole);
使用@SelectKey注解,以下代码是前面XML中配置的 selectKey
<selectKey keyColumn="id" resultType="long" keyProperty="id" order="AFTER"> SELECT LAST_INSERT_ID() </selectKey>
3.3 @Update 和@Delete注解
@Update({"update sys_role", "set role_name = #{roleName},", "enabled = #{enabled},", "create_by = #{createBy},", "create_time = #{createTime, jdbcType=TIMESTAMP}", "where id = #{id}" }) int updateById(SysRole sysRole); @Delete("delete from sys_role where id = #{id}") int deleteById(Long id);
3.4 多表关联查询的@One 和@Many注解
数据库使用:oracle
图形化界面:PL/SQL Developer
案例的介绍:一个销售旅游产品的网站。
查询的要求:根据订单的ID查询,订单的详细信息 ,这是一个多表关联查询。使用mybatis注解+接口实现SSM整合,把查询结果反馈到JSP。
Product
public class Product { private String id; // 主键 private String productNum; // 编号 唯一 private String productName; // 名称 private String cityName; // 出发城市 @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm") private Date departureTime; // 出发时间 private String departureTimeStr; //为了页面显示,数据库里没有的字段 private double productPrice; // 产品价格 private String productDesc; // 产品描述 private Integer productStatus; // 状态 0 关闭 1 开启 private String productStatusStr; //为了页面显示,数据库里没有的字段 //部分实体类的代码省略get/set方法
Orders
//订单表的实体类 public class Orders { private String id; private String orderNum; private Date orderTime; private String orderTimeStr; private int orderStatus; private int peopleCount; private Product product; private List<Traveller> travellers; private Member member; private Integer payType; private String payTypeStr; private String orderDesc; private String orderStatusStr; //============================================ //通过在SET方法的方法体里直接赋值字符串内容实现 public String getOrderStatusStr() { //订单状态 (0未支付 1已支付) if(orderStatus ==0){ orderStatusStr= "未支付"; }else if (orderStatus ==1){ orderStatusStr= "已支付"; } return orderStatusStr; } //============================================= //以下省略一些GET/SET方法
package cn.bjut.ssm.dao; import cn.bjut.ssm.domain.Traveller; import org.apache.ibatis.annotations.Select; import java.util.List; public interface ITravellerDao { @Select("select * from traveller where id in ( select travellerId from order_traveller where orderId=#{ordersId})") public List<Traveller> findByOrdersId(String ordersId) throws Exception; }
package cn.bjut.ssm.dao; import cn.bjut.ssm.domain.Member; import org.apache.ibatis.annotations.Select; public interface IMemberDao { //通过订单ID查询会员,目的是供订单查询的@Select下@Result注解引用 @Select("select * from MEMBER where id=#{memberId}") Member findById(String memberId) throws Exception; }
//通过订单主键ID查询订单详情(多表关联查询) @Select("select * from ORDERS where id = #{ordersId}" ) //oracle数据库TABLE名不区分大小写 @Results({ //为了网页显示的后缀Str类型的实体类属性不用对应出来 @Result(property ="id",column = "id",id = true ), //主键声明id = true @Result(property ="orderNum",column = "orderMum"), @Result(property ="orderTime",column = "orderTime"), @Result(property ="orderStatus",column = "orderStatus"), @Result(property ="peopleCount",column = "peopleCount"), @Result(property ="payType",column = "payType"), @Result(property ="orderDesc",column = "orderDesc"), //多表关联查询,声明“引用实体类”的封装通过:javaType= Xxx实体类.class @Result(property ="product",column = "productId",javaType = Product.class ,one [email protected](select = "cn.bjut.ssm.dao.IProductDao.findById")), @Result(property ="member",column = "memberId",javaType = Member.class ,one [email protected](select = "cn.bjut.ssm.dao.IMemberDao.findById")), //通过中间表查询多对多关系,返回一个其它实体类的List集合 @Result(property = "travellers",column ="id",javaType = java.util.List.class,many = @Many(select = "cn.bjut.ssm.dao.ITravellerDao.findByOrdersId")) }) public Orders findById(String ordersId)throws Exception;
====================
end
原文地址:https://www.cnblogs.com/MarlonKang/p/11491217.html