MyBatis從入門到精通(第3章): MyBatis註解方式的基本使用

MyBatis 註解方式就是將 SQL 語句直接寫在DAO層的接口上。html

在黑馬2018年錄製的雙元視頻課:\08 SSM整合案例【企業權限管理系統】\07.訂單操做  有使用mybatis註解進行多表關聯查詢的案例,在下文會有使用註解的補充說明。java

這種方式的優勢是 對於需求比較簡單的系統,效率較高。缺點是 SQL 有變化時都須要從新編譯代碼, 般狀況下不建議使用MyBatis的註解方式 sql

此, (原書)本章不會進行深刻講解。 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.xmlapache

    <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 接口中添加以下註解方法
mybatis

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 語句使用別名來實現,上面的例子中已經使用過 。 除此以外還有另外兩種方式分別是:
  1. 使用mapUnderscoreToCamelCase 配置
  2. 以及使用 resultMap 方式,下面詳細說明 。

3.1.1 使用 mapUnderscoreToCamelCase 配置

在數據庫中,因爲大多數數據庫設置不區分大小寫 ,所以下畫線方式的命名很常見,如 user_name 、 user_email 。在 Java 中, 通常都使用駝峯式命名,如 userName 、 userEmail 。

由於數據庫和 Java 中的這兩種命名方式很常見,所以 MyBatis 還提供 了 一個全局屬性
mapUnderscoreToCamelCase ,經過配置這個屬性爲 true 能夠自動將如下畫線方式命名的
數據庫列映射到 Java對象的駝峯式命名屬性中。這個屬性默認爲 false ,若是想要使用該功能,
須要在 MyBatis 的配置文件(第 l 章中 的 mybatis-config.xml 文件)中增長以下配置。

oracle

    <settings>
   
        <!-- 其餘mybatis配置 -->
        <setting name=" mapUnderscoreToCamelCase" value="true"/>
    </settings>

使用這種配置方式不須要手動指定別名 , MyBatis 字段按照 「下畫線轉駝峯」的方式 自動app

映射,@Select 註解中的 SQL 能夠寫成以下這種方式。dom

    @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 方法,代碼以下
maven

    @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、testSelectById二、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 =@One(select = "cn.bjut.ssm.dao.IProductDao.findById")),
            @Result(property ="member",column = "memberId",javaType = Member.class ,one =@One(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

相關文章
相關標籤/搜索