MyBatis進(jìn)階

對象之間的關(guān)系:

關(guān)聯(lián)關(guān)系:A對象依賴B對象,并且把B對象作為A對象的一個屬性,則A和B是依賴關(guān)系.

** 按照多重性分:**
1).一對一:一個A對象屬于一個B對象,一個B對象屬于一個A對象.
2).一對多:一個A對象包含多個B對象.
3).多對一:多個A對象屬于一個B對象,并且每個A對象只能屬于一個B對象.
4).多對多:一個A對象屬于多個B對象,一個B對象屬于多個A對象.
按照導(dǎo)航性分:如果通過A對象中的某一個屬性可以訪問該屬性對應(yīng)的B對象,則說A可以導(dǎo)航到B.
1).單向:只能從A通過屬性導(dǎo)航到B,B不能導(dǎo)航到A.(較多)
2).雙向:A可以通過屬性導(dǎo)航到B,B也可以通過屬性導(dǎo)航到A.
判斷方法:
1,判斷都是從對象的實例上面來看的;
2,判斷關(guān)系必須確定一對屬性;
3,判斷關(guān)系必須確定具體需求;
無論是一對多還是多對一都應(yīng)該在多方設(shè)置外鍵

單向many2one(多對一)

項目結(jié)構(gòu)劃分 ![ ![Snip20170710_19.png](http://upload-images.jianshu.io/upload_images/5220087-b62f8650b7d08264.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) ](http://upload-images.jianshu.io/upload_images/5220087-623b65933633efe3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

domain文件夾:創(chuàng)建兩個實體類 Department和Employee
Department.java

@Setter@Getter
public class Department {
private Long id;
private String name;
@Override
public String toString() {
return "Department [id=" + id + ", name=" + name + "]";
}
}

Employee.java

@Setter@Getter
public class Employee {
private Long id;
private String name;
private Department dept;
@Override
public String toString() {
return "Employee [id=" + id + ", name=" + name + "]";
}
}
mapper

EmployeeMapper.java

public interface EmployeeMapper {
void save(Employee e);
Employee get(Long id);
//體現(xiàn)多對一
List<Employee> list();
}

DepartmentMapper.java

public interface DepartmentMapper {
void save(Department dept);
    Department get(Long id);
List<Department> list();
}

EmployeeMapper.xml

<mapper namespace="com.jd.many2one.mapper.EmployeeMapper">
<resultMap type="com.jd.many2one.domain.Employee" id="base_mapper">
    <id property="id" column="id" />
    <result property="name" column="name" />
    <!-- 配置多對一的關(guān)聯(lián)映射關(guān)系
        property:關(guān)聯(lián)對象的屬性名
        javaType:關(guān)聯(lián)對象的類型
        select:查詢到關(guān)聯(lián)對象需要發(fā)送的SQL語句
        column:指定執(zhí)行該SQL需要的參數(shù)所在的列名-->
    <association property="dept" javaType="com.jd.many2one.domain.Department">
        <result property="id" column="did" />
        <result property="name" column="dname" />
    </association>
<!-- <association property="dept"
        javaType="com.jd.many2one.domain.Department">
        <result property="id" column="did" />
        <result property="name" column="dname" />
    </association> -->
</resultMap>
<insert id="save" useGeneratedKeys="true" keyColumn="id"
    keyProperty="id">
    insert into employee(name,dept_id)
    values(#{name},#{dept.id})
</insert>
<select id="get" resultMap="base_mapper">
    select * from employee where id=#{id}
</select>
<select id="list" resultMap="base_mapper">
    <!--內(nèi)聯(lián)查詢方式 -->
    select e.id,e.name,d.id did,d.name
    dname from employee e left join
    department d on e.dept_id=d.id
</select>
   </mapper>

DepartmentMapper.xml

<mapper namespace="com.jd.many2one.mapper.DepartmentMapper">
<resultMap type="com.jd.many2one.domain.Department" id="base_mapper">
    <id property="id" column="id" />
    <result property="name" column="name" />
</resultMap>

<insert id="save" useGeneratedKeys="true" keyColumn="id"
    keyProperty="id">
    insert into department(name) values(#{name})
</insert>
<select id="get" resultMap="base_mapper">
    select *from department where
    id=#{id}
</select>
<select id="list" resultMap="base_mapper">
    select * from department
</select>
</mapper>

配置文件mybatis-config.xml

<!-- 取別名 -->
<typeAliases>
    <!-- <typeAlias type="com.jd.pss.domain.User" alias="User" /> -->
    <!-- 指定掃描哪些包中的類,自動為其生成別名,默認(rèn)是使用類的簡單名稱 -->
    <package name="com.jd.pss.domain" />
</typeAliases>
<environments default="dev">
    <environment id="dev">
        <transactionManager type="JDBC" />
        <dataSource type="POOLED">
            <property name="driver" value="${driverClassName}" />
            <property name="url" value="${url}" />
            <property name="username" value="${username}" />
            <property name="password" value="${password}" />
        </dataSource>
    </environment>
</environments>
//映射器
<mappers>
    <mapper resource="com/jd/one2many/mapper/DepartmentMapper.xml" />
    <mapper resource="com/jd/one2many/mapper/EmployeeMapper.xml" />
    <mapper resource="com/jd/many2one/mapper/EmployeeMapper.xml" />
    <mapper resource="com/jd/many2one/mapper/DepartmentMapper.xml" />
</mappers>
</configuration>

工具類MyBatisUtil.java

public class MyBatisUtil {
private MyBatisUtil() {
}
private static SqlSessionFactory fac;
static {
    try {
        fac = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
    } catch (IOException e) {
        e.printStackTrace();
    }
}
public static SqlSession getSession() {
    return fac.openSession();
}
}

測試類
//添加操作主要是通過創(chuàng)建Employee對象和Department對象通過外鍵將兩者關(guān)聯(lián)起來
要先保存部門獲取部門再保存員工 因為兩者已經(jīng)建立好關(guān)系了Employee對象會調(diào)用:

<insert id="save" useGeneratedKeys="true" keyColumn="id"
    keyProperty="id">
    insert into employee(name,dept_id)
    values(#{name},#{dept.id})
</insert>

Department對象會調(diào)用:

<insert id="save" useGeneratedKeys="true" keyColumn="id"
    keyProperty="id">
    insert into department(name) values(#{name})
</insert>

同樣get和list也會到mapper.xml文件中找到對應(yīng)的方法來執(zhí)行相關(guān)方法

EmployeeMapper.xml
DepartmentMapper.xml

public class Many2OneTest

public class Many2OneTest {

@Test
public void testSave() {
    Employee e = new Employee();
    e.setName("CoderZS");
    Employee e2 = new Employee();
    e2.setName("CoderJ");

    Department dept = new Department();
    dept.setName("UI");
    
    //建立兩者之間的關(guān)系
    e.setDept(dept);
    e2.setDept(dept);
    //先保存部門,獲取到部門的編號
    SqlSession session = MyBatisUtil.getSession();
    DepartmentMapper deptMapper = session.getMapper(DepartmentMapper.class);
    deptMapper.save(dept);
    //再保存員工,使用上面的部門編號
    EmployeeMapper empMapper = session.getMapper(EmployeeMapper.class);
    empMapper.save(e);
    empMapper.save(e2);
    session.commit();
    session.close();

}

@Test
public void testGet() {
    SqlSession session = MyBatisUtil.getSession();
    EmployeeMapper empMapper = session.getMapper(EmployeeMapper.class);
    Employee emp = empMapper.get(41L);
    System.out.println(emp);
    //清空一級緩存
    session.clearCache();
    Employee emp2 = empMapper.get(41L);
    System.out.println(emp2);
    session.close();

}

@Test
public void testList() {
    SqlSession session = MyBatisUtil.getSession();
    EmployeeMapper empMapper = session.getMapper(EmployeeMapper.class);
    List<Employee> emps = empMapper.list();
    for (Employee employee : emps) {
        System.out.println(employee + ":" + employee.getDept().getName());
    }
}
}

什么是延遲加載?
在查詢many方的時候,很可能不需要查詢到one方的數(shù)據(jù)(不關(guān)心),那么此時我們就沒有不要在查詢many方的數(shù)據(jù)的時候去查詢one方, 現(xiàn)在的情況是在查詢many方的時候,都會發(fā)送額外的SQL去查詢one方

解決方案:使用延遲加載
將查詢one方的操作,往后延遲,延遲到我們?nèi)ナ褂胦ne方的時候,再去查詢.在mybatis中使用延遲加載的方式(默認(rèn)是禁用的)

<!-- 啟用延遲加載 -->
<settings>
    <setting name="lazyLoadingEnabled" value="true" />
    <!-- 設(shè)置為false之后表示在訪問many方的屬性(非關(guān)聯(lián)的對象的屬性)的時候不要觸發(fā)延遲加載 -->
    <setting name="aggressiveLazyLoading" value="false" />
    <!-- 當(dāng)訪問Object中的clone方法的時候觸發(fā)延遲加載 -->
    <setting name="lazyLoadTriggerMethods" value="clone" />
</settings>

注意:在mybatis中,訪問one方任何屬性,都會觸發(fā)延遲加載

解決N+1問題

需求:在查詢Many方的時候,會去關(guān)心one的數(shù)據(jù),.此時,每次都需要去發(fā)送一條額外的SQL去查詢數(shù)據(jù)

使用上面的方式,會出現(xiàn)N+1的問題
比如,當(dāng)要查詢100員工信息的時候,同時將員工所在的部門信息一起查詢到,此時需要發(fā)送101條SQL去查詢(每個員工所在的部門都不一樣)

解決方案:
使用內(nèi)聯(lián)查詢的方式解決
使用一條SQL語句將我們所需要的所有的數(shù)據(jù)一次性的查詢到
SQL語句:select e.id,e.name, d.id, d.name from employee e left join department d on e.dept_id=d.id

單向one2many(一對多)

項目結(jié)構(gòu)劃分


項目結(jié)構(gòu)劃分

domain實體類
Department.java

@Setter@Getter
public class Department {
private Long id;
private String name;
//體現(xiàn)一對多  
private List<Employee> emps=new ArrayList<>();
@Override
public String toString() {
return "Department [id=" + id + ", name=" + name + "]";
}
}

Employee.java

@Setter@Getter
public class Employee {
private Long id;
private String name;
@Override
public String toString() {
return "Employee [id=" + id + ", name=" + name + "]";
}
}

創(chuàng)建mapper類


mapper

DepartmentMapper.java接口

public interface DepartmentMapper {
void save(Department dept);
Department get(Long id);
    List<Department> list();
void deoete(Long id);
}

EmployeeMapper.java接口

public interface EmployeeMapper {
void save(Employee e);
Employee get(Long id);
List<Employee> list();
//更新員工和部門的信息
void updateRelation(@Param("did")Long id1,@Param("eid")Long id2);
void deleteByDeptId(Long id);
}

mybatis自動將使用@Param標(biāo)簽標(biāo)記的參數(shù)封裝到一個Map集合中(自動封裝) 標(biāo)簽的value的值作為map的key,,參數(shù)真實的值作為mapvalue
注意:@Param注解在有多個參數(shù)的時候使用

使用注解解決多個參數(shù)的問題

DepartmentMapper.xml

<mapper namespace="com.jd.one2many.mapper.DepartmentMapper">
<resultMap type="com.jd.one2many.domain.Department" id="base_mapper">
    <id property="id" column="id" />
    <result property="name" column="name" />
    <!-- 發(fā)送額外sql -->
    <!-- <collection property="emps" ofType="com.jd.one2many.domain.Employee" 
        select="com.jd.one2many.mapper.EmployeeMapper.getByDeptId" column="id"> </collection> -->

    <collection property="emps" ofType="com.jd.one2many.domain.Employee">
        <result property="id" column="eid" />
        <result property="name" column="ename" />
    </collection>
</resultMap>
<insert id="save" useGeneratedKeys="true" keyColumn="id"
    keyProperty="id">
    insert into department(name) values(#{name})
</insert>

<select id="get" resultMap="base_mapper">
    <!--使用內(nèi)聯(lián)方式 解決N+1問題 -->
    select e.id eid,e.name ename,d.id,d.name from department d left join
    employee e on d.id=e.dept_id
</select>
<select id="list" resultMap="base_mapper">
    select * from department
</select>
<delete id="delete">
    delete * from department where id=#{id}
</delete>
</mapper>

EmployeeMapper.xml

<mapper namespace="com.jd.one2many.mapper.EmployeeMapper">
<resultMap type="com.jd.one2many.domain.Employee" id="base_mapper">
    <id property="id" column="id" />
    <result property="name" column="name" />
</resultMap>
<insert id="save" useGeneratedKeys="true" keyColumn="id"
    keyProperty="id">

    insert into employee(name) values(#{name})
</insert>
<select id="get" resultMap="base_mapper">
    select * from employee where id=#{id}
</select>
<select id="list" resultMap="base_mapper">
    select * from employee
</select>
<update id="updateRelation">
    update employee set dept_id=#{did} where id=#{eid}
</update>
<select id="getByDeptId" resultMap="base_mapper">
select * from department where dept_id=#{deptId}
</select>
<delete id="deleteByDeptId">
delete from employee where dept_id=#{deptId}
</delete>
</mapper>

測試類One2ManyTest

測試類One2ManyTest

public class One2ManyTest {
@Test
public void testSave() {
    Employee e = new Employee();
    e.setName("LL");
    Employee e2 = new Employee();
    e2.setName("KK");

    Department dept = new Department();
    dept.setName("develop");
    List<Employee> emps = new ArrayList<>();
    emps.add(e);
    emps.add(e2);
    dept.setEmps(emps);
    // 保存員工
    SqlSession session = MyBatisUtil.getSession();
    EmployeeMapper empMapper = session.getMapper(EmployeeMapper.class);
    empMapper.save(e);
    empMapper.save(e2);
    // 保存部門
    DepartmentMapper deptMapper = session.getMapper(DepartmentMapper.class);
    deptMapper.save(dept);
    // 發(fā)送一條更新的SQL將部門編號更新到員工表中
    for (Employee employee : dept.getEmps()) {
        empMapper.updateRelation(dept.getId(), employee.getId());
    }
    session.commit();
    session.close();
}

@Test
public void testList(){
    SqlSession session = MyBatisUtil.getSession();
    DepartmentMapper deptMapper = session.getMapper(DepartmentMapper.class);

List<Department> depts=deptMapper.list();

for (Department department : depts) {
    
    System.out.println(department);
}
}

@Test
public void testGet() throws Exception {
    SqlSession session = MyBatisUtil.getSession();
    DepartmentMapper deptMapper = session.getMapper(DepartmentMapper.class);
    Department dept = deptMapper.get(17L);
    System.out.println(dept);
    session.close();
}
@Test
public void testDelete(){
SqlSession session =MyBatisUtil.getSession();
EmployeeMapper empMapper=session.getMapper(EmployeeMapper.class);
empMapper.deleteByDeptId(16L);
DepartmentMapper deptMapper=session.getMapper(DepartmentMapper.class);
deptMapper.deoete(16L);
session.commit();
session.close();
}   
}

在保存操作中先創(chuàng)建Employee對象和Department對象通過dept.setEmps(emps);將員工和部門關(guān)聯(lián)起來然后保存員工和部門.但是在保存操作中 employee表中只保存了員工的name并沒有將員工所在部門的部門編號保存下來.我們希望在保存員工的同時將部門編號保存到員工表中我們需要定義一個updateRelation方法來更新數(shù)據(jù)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末卖哎,一起剝皮案震驚了整個濱河市蹬挺,隨后出現(xiàn)的幾起案子虐秋,更是在濱河造成了極大的恐慌栏尚,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件休涤,死亡現(xiàn)場離奇詭異,居然都是意外死亡忱详,警方通過查閱死者的電腦和手機(jī)航唆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進(jìn)店門超营,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人窝革,你說我怎么就攤上這事吴趴。” “怎么了?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長寨闹。 經(jīng)常有香客問我帖蔓,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上莱找,老公的妹妹穿的比我還像新娘骨宠。我一直安慰自己,他們只是感情好悯辙,可當(dāng)我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布拢蛋。 她就那樣靜靜地躺著,像睡著了一般蔫劣。 火紅的嫁衣襯著肌膚如雪嗦锐。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天,我揣著相機(jī)與錄音磅崭,去河邊找鬼割岛。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼攀操,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤匾效,失蹤者是張志新(化名)和其女友劉穎魔策,沒想到半個月后游岳,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體晌区,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年轨功,在試婚紗的時候發(fā)現(xiàn)自己被綠了羡滑。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片熙揍。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡析砸,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情啸罢,我是刑警寧澤蕾总,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏勇吊。R本人自食惡果不足惜针史,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一智润、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧为狸,春花似錦、人聲如沸寄疏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至犁珠,卻和暖如春威根,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工奕枝, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留忘晤,地道東北人闰蛔。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓步势,卻偏偏與公主長得像,于是被迫代替她去往敵國和親背犯。 傳聞我的和親對象是個殘疾皇子坏瘩,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,033評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法漠魏,內(nèi)部類的語法倔矾,繼承相關(guān)的語法,異常的語法柱锹,線程的語...
    子非魚_t_閱讀 31,639評論 18 399
  • 一. Java基礎(chǔ)部分.................................................
    wy_sure閱讀 3,811評論 0 11
  • 基本知識 resultMap constructor–實例化的時候通過構(gòu)造器將結(jié)果集注入到類中oidArg– ID...
    stutterr閱讀 699評論 0 0
  • 接著上一篇的進(jìn)階教程哪自,繼續(xù)學(xué)習(xí)Mybatis的一些常用用法。以便我們更好使用Mybatis禁熏。 知識點匯總 數(shù)據(jù)表一...
    Real_man閱讀 645評論 2 4
  • 腦袋不清楚壤巷,不知道自己的位置,遇事不淡定瞧毙,這是我最大的問題胧华,簡單說情商太低,每次和海星聊天宙彪,都能發(fā)現(xiàn)很多問題矩动。我是...
    葉子卷閱讀 200評論 1 1