Mybatis框架,MyBatis03

 2023-11-30 阅读 37 评论 0

摘要:十一、動態SQL【重點】 MyBatis的映射文件中支持在基礎SQL上添加一些邏輯操作,并動態拼接成完整的SQL之后再執行,以達到SQL復用、簡化編程的效果。 11.1 < sql > <mapper namespace="com.qf.mybatis.part2.dynamic.BookDao"><sql id

十一、動態SQL【重點


MyBatis的映射文件中支持在基礎SQL上添加一些邏輯操作,并動態拼接成完整的SQL之后再執行,以達到SQL復用、簡化編程的效果。

11.1 < sql >

<mapper namespace="com.qf.mybatis.part2.dynamic.BookDao"><sql id="BOOKS_FIELD"> <!-- 定義SQL片段 -->SELECT id,name,author,publish,sort</sql><select id="selectBookByCondition" resultType="com.qf.mybatis.part2.dynamic.Book"><include refid="BOOKS_FIELD" /> <!-- 通過ID引用SQL片段 -->FROM t_books</select>
</mapper>

補充:

    <!-- 抽取重復sql片段 --><sql id="user_field">select id,username,password,gender,regist_time registTimefrom t_user </sql><select id="queryUsers" resultType="User"><!-- 引用sql片段 --><include refid="user_field"/></select>

11.2 < where >

查詢是很頻繁的,如果查詢的列特別多,那就需要再DAO中寫特別多的方法,現在可以創建一個

Mybatis框架,User queryUser (User user);

方法,可以把User的屬性全部返回出來,我們可以在mapper.xml對方法的描述時做 if 判斷,想要誰那就返回誰。

那就只需要寫一個方法即可

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.qf.dao.UserDAO"><!-- 抽取重復sql片段 --><sql id="user_field">select id,username,password,gender,regist_time registTimefrom t_user</sql><select id="queryUsers" resultType="User"><!-- 引用sql片段 --><include refid="user_field"/></select><select id="queryUser" resultType="User"><include refid="user_field"/>where<if test="id != null">id=#{id}</if><if test="username != null">username=#{username}</if></select></mapper>

補充:
@before注解

    UserDAO mapper;@Before//@before注解是junit的注解,可以在下面方法執行前都執行被修飾的方法,把通用語句放進去//此處就是每次都創建一個mapper,public void init(){mapper= MyBatisUtil.getMapper(UserDAO.class);}

java_home environment variable?如果查詢多個條件是,會涉及or和and,但是前后如果有條件 if 不滿足會造成SQL語句錯誤。那就要使用where標簽,把內容包裹起來。

 <!-- where標簽:1. 補充where關鍵字2. 識別where子句中如果 以or,and開頭,會將or,and去除--><where><if test="username!=null">username=#{username}</if><if test="gender!=null">and gender=#{gender}</if></where>

11.3 < set > --針對于更新

實際更新可能只需要改某一個字段
接受一個對象,如果某個字段為空那就不需要更新。

按照之前的if標簽可進行選擇,如果修改全部字段沒問題,但是其中一個字段為null的話,if標簽里面的SQL語句后面會存在一個逗號,引起SQL語法報錯。

<update id="updateuser">UPDATE tables<!--1. 補充set2. 自動將set子句的最后的逗號去除--><!--<set><if test="username!=null">username=#{username},</if><if test="password!=null">password=#{password},</if><if test="gender!=null">gender=#{gender},</if><if test="registTime!=null">regist_time=#{registTime}</if></set>-->WHERE id = #{id}
</update>

11.4 < trim >

< trim prefix="" suffix="" prefixOverrides="" suffixOverrides="" >代替< where > 、< set >

java groupingby。prefix加前綴 suffix加后綴

trim是一個比較綜合的標簽,可以實現where和set的功能

        <!--  prefix="where" 補充where關鍵字prefixOverrides="or|and"  where子句中如果以or或and開頭,會被干掉--><trim prefix="where" prefixOverrides="or|and"><if test="username!=null">username=#{username}</if><if test="gender!=null">and gender=#{gender}</if></trim>
<update id="方法名">UPDATE table<!-- prefix="set" 補充一個setsuffixOverrides=","    自動將set子句的最后的逗號去除--><trim prefix="set" suffixOverrides=","><if test="username!=null">username=#{username},</if><if test="password!=null">password=#{password},</if><if test="gender!=null">gender=#{gender},</if><if test="registTime!=null">regist_time=#{registTime}</if></trim>WHERE id = #{id}
</update>

11.5 < foreach >

<delete id="deleteByIds">DELETE FROM t_booksWHERE id IN<foreach collection="list" open="(" separator="," close=")"  item="id" index="i">#{id}</foreach>
</delete>
參數描述取值
collection容器類型list、array、map
open起始符(
close結束符)
separator分隔符,
index下標號從0開始,依次遞增
item當前項任意名稱(循環中通過 #{任意名稱} 表達式訪問)

補充:

public interface UserDAO {List<User> queryUsers();/*User queryUserById(@Param("id") Integer id);User queryUserByUsername(@Param("username") String username);*/User queryUser(User user);List<User>  queryUser2(User user);Integer deleteUser(@Param("id") Integer id);Integer updateUser(User user);Integer insertUser(User user);Integer deleteManyUser(List<Integer> ids);Integer insertManyUser(List<User> users);
}
    <!--foreach描述in()括號中的內容,注意輸入類型是list<>集合--><delete id="deleteManyUser" parameterType="java.util.List"><!--delete from t_user where id in (x,x,x,x,x,x)-->delete from t_user where id in<foreach collection="list" open="(" close=")" item="id9" separator=",">#{id9}</foreach></delete>

foreach描述:遍歷一個list集合,以(開頭,以)結尾,每次輸出結果存到id9的結果上,然后把id9作輸出,中間以逗號分隔。

同理可以使用foreach作添加操作

<insert id="insertManyUser" parameterType="java.util.List"><!--insert into t_user (null,x,x,x,x,x,x),(null,xxxx,xxx,xx)-->insert into t_user values<!--foreach描述:insertManyUser方法返回為list,遍歷是list--><foreach collection="list" close="" open="" item="user9" separator=",">(null,#{user9.username},#{user9.password},#{user9.gender},#{user9.registTime})</foreach></insert>
    @Testpublic void test5(){List<Integer> ids = Arrays.asList(10006, 10007, 10008, 10009);mapper.deleteManyUser(ids);MyBatisUtil.commit();//修改數據,需要對事務進行提交}//Arrays.asList() 該方法是將數組轉化成List集合的方法。@Testpublic void test6(){List<User> users = Arrays.asList(new User(null, "張三", "123", true, new Date()),new User(null, "李四", "456", false, new Date()));mapper.insertManyUser(users);MyBatisUtil.commit();}

十二、緩存(Cache)【重點


內存中的一塊存儲空間,服務于某個應用程序,旨在將頻繁讀取的數據臨時保存在內存中,便于二次快速訪問。

存在內存中的數據是頻繁被訪問,但是很少被更新的數據。

無緩存:用戶在訪問相同數據時,需要發起多次對數據庫的直接訪問,導致產生大量IO、讀寫硬盤的操作,效率低下
在這里插入圖片描述
         |
有緩存:首次訪問時,查詢數據庫,將數據存儲到緩存中;再次訪問時,直接訪問緩存,減少IO、硬盤讀寫次數、提高效率
在這里插入圖片描述

12.1 一級緩存

SqlSession級別的緩存,同一個SqlSession的發起多次同構查詢,會將數據保存在一級緩存中。

  • 注意:無需任何配置,默認開啟一級緩存。
    一級緩存默認被開啟,不需要配置
 @Testpublic void test7(){SqlSession sqlSession = MyBatisUtil.openSession();UserDAO mapper = sqlSession.getMapper(UserDAO.class);List<User> users = mapper.queryUsers();System.out.println("===========");List<User> users1 = mapper.queryUsers();//再查一次//查詢結果發現只查詢了一次,所以一級緩存默認開啟System.out.println("-------------------------------");SqlSession session = MyBatisUtil.getSession();//mybatisUtil添加getSession方法,獲取新的session//getsession方法直接返回sqlsession,不再綁定唯一UserDAO mapper1 = session.getMapper(UserDAO.class);mapper1.queryUsers();}

小結:

  1. 同一個sqlsession相同條件查詢一次就可以緩存到內存中,不需要訪問第二次數據庫。
  2. 一級緩存使用價值不大,對象已經獲取過,就不需要再次獲取了,所以需要學習使用二級緩存,范圍在sqlsessionFactory范圍,也就是整個項目上都可以對返回值全局共享。

12.2 二級緩存–使用價值更高

SqlSessionFactory級別的緩存,同一個SqlSessionFactory構建的SqlSession發起的多次同構查詢,會將數據保存在二級緩存中。

  • 注意:在sqlSession.commit()或者sqlSession.close()之后生效。
12.2.1 開啟全局緩存

< settings >是MyBatis中極為重要的調整設置,他們會改變MyBatis的運行行為,其他詳細配置可參考官方文檔。

放到mybatis-config.xml

<configuration><properties .../><!-- 注意書寫位置 --><settings><setting name="cacheEnabled" value="true"/> <!-- mybaits-config.xml中開啟全局緩存(默認開啟) --></settings><typeAliases></typeAliases>
</configuration>

注意:mybatis的配置文件的標簽有明確的順序,可以查看 configuration 標簽

<!--(properties?, settings?, typeAliases?,typeHandlers?, objectFactory?, objectWrapperFactory?,reflectorFactory?, plugins?, environments?,databaseIdProvider?, mappers?)-->
12.2.2 指定Mapper緩存

在mapper文件中加上<cache / >標簽,開啟二極緩存

<mapper namespace="com.qf.mybatis.part2.cache.BookDao"><!-- 二級緩存默認開啟的,但并不是所有的查詢結果,都會進入二級緩存 --><cache/><select id="selectBookByCondition" resultType="com.qf.mybatis.part2.cache.Book">SELECT * FROM t_books</select>
</mapper>
@Test
public void testMapperCache(){SqlSession sqlSession1 = MyBatisUtils.getSession();BookDao bookDao1 = sqlSession1.getMapper(BookDao.class);bookDao1.selectBookByCondition(new Book());sqlSession1.close(); //必須關閉SqlSession才可緩存數據//--------------------SqlSession sqlSession2 = MyBatisUtils.getSession();BookDao bookDao2 = sqlSession2.getMapper(BookDao.class);bookDao2.selectBookByCondition(new Book());sqlSession2.close(); //緩存擊中
}

小結:

  1. 必須關閉SqlSession才可緩存數據,關閉后才會進到二級緩存。
12.2.3 緩存清空并重新緩存

如果數據庫中數據被增刪改之后就需要清除緩存

@Test
public void testMapperCache(){SqlSession sqlSession1 = MyBatisUtils.getSession();BookDao bookDao1 = sqlSession1.getMapper(BookDao.class);bookDao1.selectBookByCondition(new Book());sqlSession1.close(); //必須關閉SqlSession才可緩存數據//--------------------SqlSession sqlSession3 = MyBatisUtils.getSession();BookDao bookDao3 = sqlSession3.getMapper(BookDao.class);bookDao3.deleteBookById(102);sqlSession3.commit(); //DML成功,數據發生變化,緩存清空sqlSession3.close();//--------------------SqlSession sqlSession2 = MyBatisUtils.getSession();BookDao bookDao2 = sqlSession2.getMapper(BookDao.class);bookDao2.selectBookByCondition(new Book());sqlSession2.close(); //緩存未擊中,重新查詢數據庫、重新緩存
}

使用同一個mapper刪除就會被移除。
第一次查詢,數據緩存到內存中,第二次刪除,數據被刪除持久化。第三次重新查詢,緩存未被擊中。

十三、Druid連接池–德魯伊


之前做的每一個請求都需要一個連接,整個流程是比較費時間的,并且消耗資源。

13.1 概念

Druid 是阿里巴巴開源平臺上的一個項目,整個項目由數據庫連接池、插件框架和 SQL 解析器組成。該項目主要是為了擴展 JDBC 的一些限制,可以讓程序員實現一些特殊的需求,比如向密鑰服務請求憑證、統計 SQL 信息、SQL 性能收集、SQL 注入檢查、SQL 翻譯等,程序員可以通過定制來實現自己需要的功能。

13.2 不同連接池對比

測試執行申請歸還連接 1,000,000(一百萬)次總耗時性能對比。

13.2.1 測試環境
環境版本
OSOS X 10.8.2
CPUIntel i7 2GHz 4 Core
JVMJava Version 1.7.0_05
13.2.2 基準測試結果對比
JDBC-Conn Pool1 Thread2 threads5 threads10 threads20 threads50 threads
Druid8981,1911,3241,3621,3251,459
tomcat-jdbc1,2691,3782,0292,1031,8792,025
DBCP2,3245,0555,4465,4715,5245,415
BoneCP3,7383,1503,1945,68111,01823,125
jboss-datasource4,3772,9883,6803,98032,70837,742
C3P010,84113,63710,68211,05514,49720,351
Proxool16,33716,18718,310(Ex)25,94533,706(Ex)39,501 (Ex)
13.2.3 測試結論
  • Druid 是性能最好的數據庫連接池,tomcat-jdbc 和 druid 性能接近。
  • Proxool 在激烈并發時會拋異常,不適用。
  • C3P0 和 Proxool 都相當慢,影響 sql 執行效率。
  • BoneCP 性能并不優越,采用 LinkedTransferQueue 并沒有能夠獲得性能提升。
  • 除了 bonecp,其他的在 JDK 7 上跑得比 JDK 6 上快。
  • jboss-datasource 雖然穩定,但性能很糟糕。

13.3 配置pom.xml

引入Druid依賴

<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.16</version>
</dependency>

13.4 創建DruidDataSourceFactory

MyDruidDataSourceFactory并繼承PooledDataSourceFactory,并替換數據源。

package com.qf.mybatis.part2.utils;import com.alibaba.druid.pool.DruidDataSource;
import org.apache.ibatis.datasou	rce.pooled.PooledDataSourceFactory;public class MyDruidDataSourceFactory extends PooledDataSourceFactory {public MyDruidDataSourceFactory() {this.dataSource = new DruidDataSource();//替換數據源}
}
//會返回德魯伊連接池的一個對象。

13.5 修改mybatis-config.xml

mybatis-config.xml中連接池相關配置。

<!--連接池--><!-- 數據連接參數  --><dataSource type="com.qf.datasource.MyDruidDataSourceFactory"><property name="driverClass" value="${jdbc.driver}"/><!-- &轉義&amp; --><property name="jdbcUrl" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/></dataSource>

注意:< property name=“屬性名” />屬性名必須與com.alibaba.druid.pool.DruidAbstractDataSource中一致。

十四、PageHelper – 分頁


14.1 概念

PageHelper是適用于MyBatis框架的一個分頁插件,使用方式極為便捷,支持任何復雜的單表、多表分頁查詢操作。

14.2 訪問與下載

官方網站:https://pagehelper.github.io/

下載地址:https://github.com/pagehelper/Mybatis-PageHelper

14.3 開發步驟

PageHelper中提供了多個分頁操作的靜態方法入口。

14.3.1 引入依賴

pom.xml中引入PageHelper依賴。

<dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId><version>5.1.10</version>
</dependency>
14.3.2 配置MyBatis-config.xml

在MyBatis-config.xml中添加< plugins >。

<configuration><typeAliases></typeAliases><plugins><!-- com.github.pagehelper為PageHelper類所在包名 --><plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin></plugins><environments>...</environments>
</configuration>
14.3.3 PageHelper應用方式

使用PageHelper提供的靜態方法設置分頁查詢條件。

 @Testpublic void testPage(){UserDAO mapper = MyBatisUtil.getMapper(UserDAO.class);//在查詢前,設置分頁  查詢第一頁,每頁2條數據// PageHelper特點: 對其之后的第一個查詢,進行分頁功能追加PageHelper.startPage(1,2);List<User> users = mapper.queryUsers();for (User user : users) {System.out.println(user);}// 將查詢結果 封裝到 PageInfo對象中PageInfo<User> pageInfo = new PageInfo(users);System.out.println("================");}

在這里插入圖片描述

14.4 PageInfo對象

PageInfo對象中包含了分頁操作中的所有相關數據。

PageInfo結構圖
在這里插入圖片描述
14.4.1 PageInfo應用方式

使用PageInfo保存分頁查詢結果。

@Test
public void testPageInfo(){UserDao userDao = MyBatisUtils.getMapper(UserDao.class);PageHelper.startPage(6, 2);List<User> users = userDao.selectAllUsers();PageInfo<User> pageInfo = new PageInfo<User>(users);//將分頁查詢的結果集保存在PageInfo對象中System.out.println(pageInfo);
}
14.4.2 注意事項
  • 只有在PageHelper.startPage()方法之后的第一個查詢會有執行分頁。
  • 分頁插件不支持帶有“for update”的查詢語句。
  • 分頁插件不支持“嵌套查詢”,由于嵌套結果方式會導致結果集被折疊,所以無法保證分頁結果數量正確。。
14.4.3 分頁練習

使用Servlet+JSP+MyBatis+分頁插件,完成分頁查詢功能。

十五、補充【了解】


以下內容并非必備知識,了解即可。

15.1 MyBatis注解操作

通過在接口中直接添加MyBatis注解,完成CRUD。

  • 注意:接口注解定義完畢后,需將接口全限定名注冊到mybatis-config.xml的< mappers >中。
  • 經驗:注解模式屬于硬編碼到.java文件中,失去了使用配置文件外部修改的優勢,可結合需求選用。
<mappers><mapper class="com.qf.mybatis.part1.annotations.UserMapper" /><!-- class="接口全限定名"-->
</mappers>
15.1.1 查詢
public interface UserMapper {@Select("SELECT * FROM t_users WHERE id = #{id}")public User selectUserById(Integer id);@Select("SELECT * FROM t_users WHERE id = #{id} AND password = #{pwd}")public User selectUserByIdAndPwd_annotation(@Param("id") Integer id, @Param("pwd") String password);
}
15.1.2 刪除
@Delete(value = "DELETE FROM t_users WHERE id = #{id}")
public int deleteUser(Integer id);
15.1.3 修改
@Update("UPDATE t_users SET name = #{name} , password = #{password} , salary = #{salary} , birthday = #{birthday} WHERE id = #{id}")
public int updateUser(User user);
15.1.4 插入
@Insert("INSERT INTO t_users VALUES(#{id},#{name},#{password},#{salary},#{birthday},null)")
public int insertUser(User user);@Options(useGeneratedKeys = true , keyProperty = "id") // 自增key,主鍵為id
@Insert("INSERT INTO t_users VALUES(#{id},#{name},#{password},#{salary},#{birthday},null)")
public int insertUserGeneratedKeys(User user);

補充:UserDAO接口

    @Select("SELECT id,username,password,gender,regist_time FROM t_user")List<User> queryUsers();@Select("SELECT id,username,password,gender,regist_time\n" +" FROM t_user\n" +" WHERE id = #{id}")User queryUserById(@Param("id") Integer id);@Delete("delete from t_user\n" +"        where id=#{id}")Integer deleteUser(@Param("id") Integer id);@Update("update t_user\n" +"        set username=#{username},password=#{password},gender=#{gender},regist_time=#{registTime}\n" +"        where id=#{id}")Integer updateUser(User user);

主鍵回填:

  @Options(useGeneratedKeys = true , keyProperty = "id") // 自增key,主鍵為id@Insert("insert into t_user values(#{id},#{username},#{password},#{gender},#{registTime})")Integer insertUser(User user);

Test

    @Testpublic void test1(){UserDAO mapper = MyBatisUtil.getMapper(UserDAO.class);List<User> users = mapper.queryUsers();for (User user : users) {System.out.println(user);}System.out.println("============");User user = mapper.queryUserById(10011);System.out.println(user);//mapper.deleteUser(10011);User new_user = new User(null, "new_user", "1111", true, new Date());//mapper.insertUser(new_user);System.out.println("新用戶id:"+new_user.getId());//mapper.updateUser(new User(10015,"張三2","11111",true,new Date()));MyBatisUtil.commit();}

注解開發: 第一步寫DAO,第二步寫注解,第三步注冊到mybatis-config.xml

小結注解:

  1. 注解會產生耦合,不建議使用。
  2. 使用mapper更方便。

15.2 $符號的應用場景

${attribute} 屬于字符串拼接SQL,而非預編譯占位符,會有注入攻擊問題,不建議在常規SQL中使用,常用于可解決動態生降序問題。

15.2.1 $符號參數綁定
public List<User> selectAllUsers1(User user); // ${name} ${id} 可獲取user中的屬性值
public List<User> selectAllUsers2(@Param("rule") String rule); //必須使用@Param否則會作為屬性解析
<select id="selectAllUsers1" resultType="user">SELECT * FROM t_users WHERE name = '${name}' or id = ${id} <!-- 拼接name和id,如果是字符類型需要用單引號:'${name}' -->
</select>
<select id="selectAllUsers2" resultType="user">SELECT * FROM t_users ORDER BY id ${rule} <!-- 拼接 asc | desc -->
</select>
User user = new User(....);
List<User> ulist1 = userDAO.selectAllUsers1(user); //調用時傳入user對象List<User> ulist2 = userDao.selectAllUsers2("desc"); //調用時傳入asc | desc
15.2.2 $符號注入攻擊
<select id="selectUsersByKeyword" resultType="user">SELECT * FROM t_userWHERE name = '${name}' <!-- 會存在注入攻擊  比如傳入參數是 【String name = "tom' or '1'='1";】-->
</select>
注入攻擊,拼接的內容,改變了原sql語義,被攻擊!
在這里插入圖片描述
 |

$符小結:
缺點:

  1. 使用${}在涉及字符字段的時候需要在SQL中加上單引號,#{}是自動加的。
    在這里插入圖片描述在這里插入圖片描述
  2. 如果寫的是#{arg0},就會找這個參數對應類型的get方法獲取arg0的值。也就是說簡單類型的就必須加上@parm注解,如果是引用就不需要加

在這里插入圖片描述
3. 本質區別:用#號取值,用的是一個占位符,$是直接進行拼接
在這里插入圖片描述在這里插入圖片描述

#號使用占位符

/*** 1.占位符:規避sql注入風險* 2.占位符要和列相關位置才可以使用* 原則:填充數據,要和列相關* select * from t_user where id=?* insert into t_user values(?,?,?)* update t_user set username=?,password=?* @throws ClassNotFoundException* @throws SQLException*/@Testpublic void test2() throws ClassNotFoundException, SQLException {Class.forName("com.mysql.jdbc.Driver");Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis_shine?useUnicode=true&characterEncoding=utf-8","root","111111");//要填充的數據String username = "shine_66' or '1'='1";String rule = "desc";String sql = "select * from t_user where username=?";String sql2 = "select * from t_user order by id ?";PreparedStatement preparedStatement = connection.prepareStatement(sql2);// 在占位符上 填充descpreparedStatement.setString(1,rule);ResultSet resultSet = preparedStatement.executeQuery();while(resultSet.next()){System.out.println(resultSet.getInt("id"));System.out.println(resultSet.getString("username"));}}

上述SQL變成select * from t_user order by id=“shine_66’ or ‘1’='1”
數據庫中是找不到這個字符的

$直接拼接


/*** 1. sql注入風險* 2. 隨意拼接* @throws ClassNotFoundException* @throws SQLException*/
@Testpublic void test3() throws ClassNotFoundException, SQLException {Class.forName("com.mysql.jdbc.Driver");Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis_shine?useUnicode=true&characterEncoding=utf-8","root","111111");//要填充的數據String username = "shine_xxx' or '1'='1";String rule = "desc";//sq拼接填充數據  select * from t_user where username='shine_66'//sq拼接填充數據  select * from t_user where username='shine_xxx' or '1'='1'// 當拼接sql片段,有sql注入風險,外界參數改變原有sql的語義String sql = "select * from t_user where username='"+username+"'";String sql2 = "select * from t_user order by id "+rule;Statement statement = connection.createStatement();ResultSet resultSet = statement.executeQuery(sql2);while(resultSet.next()){System.out.println(resultSet.getInt("id"));System.out.println(resultSet.getString("username"));}}

綜上:當拼接sql片段,有sql注入風險,外界參數改變原有sql的語義。原則上能不用拼接就不用。

  1. $的使用場景,在sql語句上動態填充:如排序
	    String rule = "desc";String sql2 = "select * from t_user order by id "+rule;

15.3 MyBatis處理關聯關系-嵌套查詢【了解】

思路:查詢部門信息時,及聯查詢所屬的員工信息。

  • DepartmentDao接口中定義selectDepartmentById,并實現Mapper。
  • EmployeeDao接口中定義selectEmployeesByDeptId,并實現Mapper,
  • 當selectDepartmentById被執行時,通過< collection >調用selectEmployeesByDeptId方法,并傳入條件參數。

現在是查詢兩次,員工部門表
員工查員工,部門查部門。


public interface EmployeeDAO {// 查詢某個部門下的所有員工List<Employee> queryEmployeeByDeptId(@Param("deptId") Integer deptId);
}
<resultMap id="emp_dept" type="Employee"><id column="id" property="id"></id><result column="name" property="name"></result><result column="salary" property="salary"></result><!--<association property="department" javaType="Department"><id column="deptId" property="id"></id><result column="deptName" property="name"></result><result column="location" property="location"></result></association>--><association property="department" javaType="Department"select="com.qf.dao.DepartmentDAO.queryDepartmentById"column="dept_id"<--給到的屬性-->></association></resultMap><select id="queryEmployeeByDeptId" resultType="Employee">select id,name,salaryfrom t_employeeswhere dept_id=#{deptId}</select>

在這里插入圖片描述
可以查出當前部門下的所有員工。
先查出部門,再通過部門使用查詢員工的方法進行嵌套查詢。

DepartmentDAO mapper = MyBatisUtil.getMapper(DepartmentDAO.class);Department department = mapper.queryDepartmentById(1);System.out.println(department);List<Employee> employees = department.getEmployees();for (Employee employee : employees) {System.out.println(employee);}

在這里插入圖片描述
反過來查詢員工的部門信息也是可以的

15.3.1 主表查詢

定義selectEmployeesByDeptId,并書寫Mapper,實現根據部門ID查詢員工信息

public interface EmployeeDao {/*** 根據部門編號查詢員工信息* @param did 部門編號* @return 該部門中的所有員工*/public List<Employee> selectEmployeeByDeptId(@Param("did") String did);
}
<mapper namespace="com.qf.mybatis.part2.one2many.EmployeeDao"><!-- 根據部門編號查詢所有員工 --><select id="selectEmployeeById" resultType="employee" >SELECT id,name,salary,dept_id FROM t_employees WHERE dept_id = #{did}</select>
</mapper>
15.3.2 及聯調用
定義selectDepartmentById,并書寫Mapper,實現根據部門ID查詢部門信息,并及聯查詢該部門員工信息
public interface DepartmentDao {/*** 查詢部門信息* @param id* @return*/public Department selectDepartmentById(@Param("id") String id);
}
<mapper namespace="com.qf.mybatis.part2.one2many.DepartmentDao"><resultMap id="departmentResultMap" type="department"><id property="id" column="id" /><result property="name" column="name" /><result property="location" column="location" /><!-- column="傳入目標方法的條件參數"  select="及聯調用的查詢目標"--><collection property="emps" ofType="Employee" column="id" select="com.qf.mybatis.part2.one2many.EmployeeDao.selectEmployeeByDeptId" /></resultMap><select id="selectAllDepartments" resultMap="departmentResultMap">SELECT id , name , locationFROM t_departmentsWHERE id = #{id}</select>
</mapper>
15.3.3 延遲加載
mybatis-config.xml中開啟延遲加載
<settings><setting name="lazyLoadingEnabled" value="true"/> <!-- 開啟延遲加載(默認false) -->
</settings>
  • 注意:開啟延遲加載后,如果不使用及聯數據,則不會觸發及聯查詢操作,有利于加快查詢速度、節省內存資源。

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/2/186151.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息