※事前規劃
假裝有一個USER_NAME表,因為之前沒規劃好,想多加幾個欄位,怕在這張表增加以後會影響現有的行為,所以增加一張表,叫USER_DATA,這樣就成了一個一對一的關聯CREATE TABLE USER_NAME( USERID VARCHAR(10) , NAME VARCHAR(20) , CONSTRAINT USER_PK PRIMARY KEY(USERID) ); CREATE TABLE USER_DATA( USERID VARCHAR(10) , AGE NUMBER(3) , BIRTHDAY DATE , CONSTRAINT USER_DATA_PK PRIMARY KEY(USERID) , CONSTRAINT USER_DATA_FK FOREIGN KEY(USERID) REFERENCES USER_NAME(USERID) ON DELETE CASCADE ); COMMENT ON TABLE USER_DATA IS '使用者資料表'; COMMENT ON COLUMN USER_DATA.USERID IS '使用者id'; COMMENT ON COLUMN USER_DATA.AGE IS '使用者年齡'; COMMENT ON COLUMN USER_DATA.BIRTHDAY IS '使用者生日'; COMMENT ON TABLE USER_NAME IS '使用者名稱表'; COMMENT ON COLUMN USER_NAME.USERID IS '使用者id'; COMMENT ON COLUMN USER_NAME.NAME IS '使用者姓名'; INSERT INTO USER_NAME(USERID, NAME)VALUES(1, 'xxx'); INSERT INTO USER_DATA(USERID, AGE, BIRTHDAY)VALUES(1, 20, TO_DATE('19990125', 'YYYYMMDD'));
因為是雙向,所以兩張java都各增加一個屬性連到對方:
public class UserName { private String userId; private String name; private UserData userData; //setter/getter... } public class UserData { private String userId; private Integer age; private Date birthday; private UserName userName; //setter/getter... }
※association設定
因為是雙向,兩張xml都要設定,UserName.xml:<mapper namespace="ooo.UserName"> <resultMap type="UserName" id="mapperUserName"> <id property="userId" column="USERID" /> <result property="name" column="NAME" /> <association property="userData" column="USERID" javaType="UserData" select="xxx.UserData.getUserDataById"/> </resultMap> <select id="getUserNameById" parameterType="int" resultMap="mapperUserName"> SELECT * FROM USER_NAME WHERE USERID = #{userId} </select> </mapper>
UserData.xml:
<mapper namespace="xxx.UserData"> <resultMap type="UserData" id="mapperUserData"> <id property="userId" column="USERID" /> <result property="age" column="AGE" /> <result property="birthday" column="BIRTHDAY" /> <association property="userName" column="USERID" javaType="UserName" select="ooo.UserName.getUserNameById" /> </resultMap> <select id="getUserDataById" parameterType="int" resultMap="mapperUserData"> SELECT * FROM USER_DATA WHERE USERID = #{userId} </select> </mapper>
javaType因為有別名的關係,所以才這樣寫,select要namespace.id,選對方的
測試類:
SqlSession sqlSession = MyBatisSessionFactory.getSession(); UserName un = sqlSession.selectOne("ooo.UserName.getUserNameById", 1); System.out.println("getUserId=" + un.getUserId()); System.out.println("getName=" + un.getName()); if(un.getUserData() != null){ System.out.println("======================================"); System.out.println("getAge=" + un.getUserData().getAge()); System.out.println("getBirthday=" + un.getUserData().getBirthday()); } System.out.println("----------------------------------------"); UserData ud = sqlSession.selectOne("xxx.UserData.getUserDataById", 1); System.out.println("getUserId=" + ud.getUserId()); System.out.println("getAge=" + ud.getAge()); System.out.println("getBirthday=" + ud.getBirthday()); if(ud.getBirthday() != null){ System.out.println("======================================"); System.out.println("getName=" + ud.getUserName().getName()); } MyBatisSessionFactory.closeSession();
如果不設association,連到對方的屬性會是null
※一對一關聯的三種方式
上面的方式是使用第三種方式,會有兩條 SQL 語句,其他兩種都一條<resultMap type="mp.bean.Emp" id="association1"> <!-- java bean 和 資料庫名稱一樣可不寫 --> <result column="dname" property="dept.dName"/> <result column="loc" property="dept.loc"/> </resultMap> <resultMap type="mp.bean.Emp" id="association2"> <!-- java bean 就算和資料庫名稱一樣也要寫,不寫就是 null --> <id column="empno" property="empno" /> <result column="ename" property="ename" /> <association property="dept" javaType="mp.bean.Dept"> <!-- java bean 就算和資料庫名稱一樣也要寫,不寫就是 null --> <id column="deptNo" property="deptNo" /> <result column="dName" property="dName" /> </association> </resultMap> <select id="getEmpById" resultMap="association1"> select empno, ename, job, mgr, hiredate, sal, comm, e.deptno, d.dname, d.loc from emp e, dept d where e.deptno = d.deptno and empno = #{id} </select> <resultMap type="mp.bean.Emp" id="association3"> <!-- java bean 和 資料庫名稱一樣可不寫 --> <association property="dept" column="deptno" select="mp.bean.dao.DeptMapper.getDeptById" /> </resultMap> <select id="getEmp2Step" resultMap="association3"> select * from emp where empno = #{id} </select> ------------------------------------------------------- <mapper namespace="mp.bean.dao.DeptMapper"> <select id="getDeptById" resultType="mp.bean.Dept"> select * from dept where deptno = #{deptNo} </select> </mapper>
※第一種是用「.」的方式,dept 是 java bean 的欄位名稱
※第二種都是 SQL 的功,缺點是什麼都要寫,否則就是 null
※第三種裡的 select 是連到其他 mapper 的 SQL,property 是 java bean 的欄位名稱
column 是從 getEmp2Step 取到的欄位名稱,有很多,當然是給要關聯的欄位名稱
第三種是為了提高效能用的,在全域的 setting 有兩個可以設定:
1.lazyLoadingEnabled:true為懶加載,但只要sql的xml裡的屬性fecthType有設定,不管是lazy或eager,都會被fecthType給覆蓋,可以在全域設定懶加載,針對特定的sql不使用懶加載,預設為 false
2.aggressiveLazyLoading:和 lazyLoadingEnabled 相反,false為懶加載;只要一給true,lazyLoadingEnabled、fetchType 都沒用了,預設為 false,但小於等於 3.4.1 版是 true,所以 3.4.1 之前如果不設為 false,lazyLoadingEnabled 會沒有用
沒有留言:
張貼留言