(3)-mybatis之註解

上次分別總結了mybatis基礎
mybatis詳解這次接着總結

註解開發

MyBatis 最初是一個 XML 驅動的框架。

配置信息是基於 XML 的,而且映射語句也是定義在 XML 中的。

隨着技術的更新發展,對於開發效率要求也原來越高,特別是一些小型項目;越來越多的框架開始支持註解。

到MyBatis3時,MyBatis對註解有了完善的支持,利用註解可以在一些情況下提高開發效率

但不幸的是,Java 註解的的表達力和靈活性十分有限。儘管很多時間都花在調查、設計和試驗上, 最強大的 MyBatis 映射並不能用註解來構建
常用註解

@Insert:實現新增
@Update:實現更新
@Delete:實現刪除
@Select:實現查詢
@Result:實現結果集封裝
@Results:可以與@Result 一起使用,封裝多個結果集
@ResultMap:實現引用@Results 定義的封裝
@One:實現一對一結果集封裝
@Many:實現一對多結果集封裝
@SelectProvider: 實現動態 SQL 映射
@CacheNamespace:實現註解二級緩存的使用

mybatis的一些配置可以去前面的文章裏面找,這裏直接上案例
首先創建接口:

package com.cx.mapper;

public class ProductMapper {
}

在mybatis-config.xml掃描這個包

<!--    指定要加載的映射文件-->
    <mappers>
        <package name="com.cx.mapper"/>
    </mappers>

創建實體類

public class Product {
    private int pid;
    private String name;
    private double price;
    private Date pdate;
    private String cid;
}

測試類:

private SqlSessionFactory sqlSessionFactory = null;
    @Before
    public void before() throws IOException {
        //創建
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
    }

mybatis註解開發會直接卸載接口裏,測試在測試類寫

1.select

接口:

 //根據id查詢  @select演示
    @Select("select * from product where pid = #{pid}")
    @Results(id = "myResult" ,value={
            @Result(id = true,column = "pid" ,property = "pid"),
            @Result(column = "pname",property = "name")
    })
    Product selectById(int id);

測試代碼:

@Test
    public void annoTest1(){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        ProductMapper mapper = sqlSession.getMapper(ProductMapper.class);
        Product product = mapper.selectById(2);
        System.out.println(product);
    }
注意:
  • @Select 括號裏寫的是SQL語句和xml文件裏寫的一樣,若是普通取值用#{} 如果是模糊查詢一樣的字符串要用單引號:‘%${}%’

  • @Results 是映射集,包含一個或多個 @Result映射,用 , 隔開
    Result裏id爲true代表主鍵,默認是flase,column是列名,property是字段名

= 當列名和字段名匹配時,註解開發是自動映射的,不匹配時要用Results註解進行定義

2. sql語句多個參數

接口方法:

//參數有多個,根據pname和price查詢
    @Select("select * from product where pname like '%${pname}%' and price = #{price}")
    @Results({
            @Result(id = true,column = "pid" ,property = "pid"),
            @Result(column = "pname",property = "name")
    })
    List<Product> selectBypnameAndPrice(@Param("pname") String pname,@Param("price") Double price);

@Param(“參數名”) 當有多個參數時要用 Param註解標明每個參數的參數名

測試類:

 @Test
    public void annoTest2(){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        ProductMapper mapper = sqlSession.getMapper(ProductMapper.class);
        List<Product> products = mapper.selectBypnameAndPrice("新疆", 38d);
        System.out.println(products);
    }

注意:

MyBatis的sql接收的參數只有一個無論實際傳了幾個

當sql語句需要多個參數時則必須將多個參數打包到一個對象中,通常是POJO或Map,上面的案例中使用了@Param註解本質就是告訴MyBatis有多個參數MyBatis會自動創建一個Map,然後將@Param的值作爲Key,然後將Map傳給sql,所以你也可以手動傳一個Map,所以上面可以寫成下面形式:

接口方法

//將參數封裝到map中
    @Select("select * from product where pname like '%${pname}%' and price = #{price}")
    @Results({
            @Result(id = true ,column = "id" ,property = "id"),
            @Result(column = "pname",property = "name")
    })
    List<Product> selectBymany(Map<String,String> params);

測試代碼:

@Test
    public void annoTest3(){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        ProductMapper mapper = sqlSession.getMapper(ProductMapper.class);
        HashMap<String,String> map = new HashMap<>();
        map.put("pname","新疆");
        map.put("price","38d");
        List<Product> products = mapper.selectBymany(map);
        System.out.println(products);
    }

3.insert方法

接口方法:

//@insert 演示
    @Insert("insert into product values(null,#{name},#{price},#{pdate},#{cid})")
    int insertProduct(Product product);

測試代碼:

@Test
    public void annoTest4(){
        //此處設置爲自動提交
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        ProductMapper mapper = sqlSession.getMapper(ProductMapper.class);
        Product product = new Product();
        product.setName("周口胡辣湯");
        product.setPrice(5d);
        int i = mapper.insertProduct(product);
        System.out.println(1);
    }

注意,插入時就算實體類字段名和數據庫表名不一致,也要按照實體類寫,而且不用寫@Results,因爲這裏我錯了,人一天三迷糊。。。。

獲取自增主鍵

在@select註解的下方添加@selectKey註解來完成對自增主鍵的獲取

 @Insert("insert into product values(null,#{name},#{price},#{pdate},#{cid})")
    @SelectKey(statement = "select last_insert_id()",keyColumn = "pid",keyProperty = "pid",resultType = Integer.class,before = false)
    int insertProduct(Product product);

SelectKey 解釋:

  • statement:要執行的方法
  • keyColumn:主鍵列名
  • keyProperty:返回對應字段名
  • resultType返回類型
  • before:插入之前返回,false代表插入之後返回

4. update

接口方法:

@Update("update product set pname = #{name},price = #{price},pdate = #{pdate},cid = #{cid} where pid = #{pid}")
    void updateByproduct(Product product);

測試代碼

@Test
    public void annoTdest5(){
        //此處設置爲自動提交
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        ProductMapper mapper = sqlSession.getMapper(ProductMapper.class);
        Product product = mapper.selectById(7);
        product.setName("新疆哈密瓜");
        product.setPrice(55);
        mapper.updateByproduct(product);
    }

5.delete

接口方法:

//刪除演示
    @Delete("delete from product where pid = #{pid}")
    void deleteById(int id);

測試代碼:

@Test
    public void annoTdest6(){
        //此處設置爲自動提交
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        ProductMapper mapper = sqlSession.getMapper(ProductMapper.class);
        mapper.deleteById(12);
        sqlSession.close();
    }

6. 動態sql

動態sql指語句中包含邏輯代碼,需要先運行邏輯代碼,最後產生sql語句,所以需要在註解中告訴MyBatis這是一個動態sql,通過語法來指定;

若想要在sql中使用各種標籤則必須添加上述根標籤,否則MyBatis會將整體作爲sql語句

接口方法聲明:

@Select("<script>" +
            "select * from products" +
            "<where>" +
            "<if test='name != null'>" +
            "and name like '%${name}%'" +
            "</if>" +
            "</where>" +
            "</script>")
@ResultMap("myResult")
List<Product> searchByName(String name);

註解:

script:標籤裏面的和xml裏面的動態sql一樣,只是用script標籤包起來了,做爲標識。

ResultMap:是調用上面Results裏面的內容,上面查詢語句裏Results設置了id,在這裏調用id就可以使用value裏面的內容
測試:

@Test
    public void SQLTest(){
        try (SqlSession session = factory.openSession()) {
            ProductsMappers mapper = session.getMapper(ProductsMappers.class);
            List<Product> list = mapper.searchByName("新疆");
            System.out.println(list);
        }
    }

7.結果映射(ResultMap)

上面已經說過基本用法,在這總結一下:

1.自定義字段與屬性對應關係

列名與字段名不匹配,需要自定義映射:
接口:

 //根據id查詢  @select演示
    @Select("select * from product where pid = #{pid}")
    @Results(id = "myResult" ,value={
            @Result(id = true,column = "pid" ,property = "pid"),
            @Result(column = "pname",property = "name")
    })
    Product selectById(int id);

測試代碼:

@Test
    public void annoTest1(){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        ProductMapper mapper = sqlSession.getMapper(ProductMapper.class);
        Product product = mapper.selectById(2);
        System.out.println(product);
    }

在這裏插入圖片描述
重複使用Results
MyBatis默認會自動映射所有字段與數據庫表列相匹配的數據,另外id表示是否爲主鍵,默認false

強調:Results可以位於對應方法的上方或下方,默認只對當前方法有效,如果需要重複使用則需要爲其指定id

 @Results(id = "myResult" ,value={
            @Result(id = true,column = "pid" ,property = "pid"),
            @Result(column = "pname",property = "name")
    })//.....中間必須間隔其他方法不能立即應用到某個ResultMap
@Select("select * from product where pname like '%${pname}%' and price = #{price}")
//通過@ResultMap註解 並傳入id來使用
@ResultMap("myResult")
List<Product> selectBymany(Map<String,String> params);

注意:
@Results的定義不能和使用它的@ResultMap一起出現,既然是重複使用的那我建議統一接口的最上面,
如果是當前要使用的並且要重用,直接使用Results即可,不需要在下面添加ResultMap就像下面這樣:

@Select("select *from kuser where username = #{name}")
@Results(id="map1",value = {
        @Result(id = true,column = "id",property = "id"),
        @Result(column = "username",property = "name"),
})
public User selectUserByName(String name);

2.關聯查詢

一對一:
@One 註解(一對一)

代替了<assocation>標籤,是多表查詢的關鍵,在註解中用來指定子查詢返回單一對象。

@One 註解屬性介紹:

select 指定用來多表查詢的 sqlmapper
fetchType 會覆蓋全局的配置參數 lazyLoadingEnabled。

使用格式:
    @Result(column=" ",property="",one=@One(select=""))
//一對一映射,根據訂單id查詢用戶信息
    @Select("select * from orders where id = #{id}")
    @Results({
            @Result(id = true,column = "id" ,property = "id"),
            @Result(column = "user_id",property = "user_id"),
            @Result(column = "user_id",property = "user",one=@One(select = "selectByuser_id"))
    })
    Order selectByOrderId(int id);
    @Select("select * from user where id = #{user_id}")
    @Results({
            @Result(id = true,column = "id",property = "id"),
            @Result(column = "username",property = "name")
    })
    User selectByuser_id(int user_id);

Result註解裏:
property對應字段名,
column表明哪個列名作爲參數,
one裏面select對應下面的方法,即爲調用下面方法按指定參數進行查詢,查到後映射到指定字段上

一對多關聯:

@Many 註解(多對一)

代替了<Collection>標籤,是是多表查詢的關鍵,
在註解中用來指定子查詢返回對象集合。

注意:聚集元素用來處理“一對多”的關係。
需要指定映射的 Java 實體類的屬性,屬性的 javaType(一般爲 ArrayList)
但是註解中可以不定義;

使用格式:
    @Result(property="",column="",many=@Many(select=""))
//一對多查詢
    @Select("select* from user where id = #{id}")
    @Results({
            @Result(id = true,column = "id",property = "id"),
            @Result(column = "username",property = "name"),
            @Result(property = "orders",column = "id",many = @Many(select = "selectOrderByUserId"))
    })
    User selectUserById(int id);
    @Select("select * from orders where user_id = #{uid}")
    @Results({
            @Result(column = "numbers",property = "number")
    })
    List<Order> selectOrderByUserId(int uid);

一對多和一對一用法都一樣,只是one註解變成了Many註解,Many註解裏的select 調用一個查詢方法,以id作爲參數,返回的結果映射到list字段去。

一對一和一對多隻能採用子查詢的方式進行。
下一篇:MyBatis之逆向工程

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章