直接看代码。部分细节,请自行参透,你懂的。。
这里先来演示ibatis2.x中的一对多映射
首先是位于CLASSPATH中的ibatis2的全局配置文件SqlMapConfig.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE sqlMapConfig PUBLIC "-//ibatis.apache.org//DTD SQL Map Config 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-config-2.dtd"> <sqlMapConfig> <settings useStatementNamespaces="true"/> <transactionManager type="JDBC"> <dataSource type="SIMPLE"> <property name="JDBC.Driver" value="oracle.jdbc.OracleDriver" /> <property name="JDBC.ConnectionURL" value="jdbc:oracle:thin:@127.0.0.1:1521:jadyer" /> <property name="JDBC.Username" value="scott" /> <property name="JDBC.Password" value="jadyer" /> </dataSource> </transactionManager> <sqlMap resource="com/jadyer/model/User.xml" /> <sqlMap resource="com/jadyer/model/People.xml" /> </sqlMapConfig>
然后是演示一对多映射用到的两个实体类
package com.jadyer.model; import java.util.List; public class User { private Integer id; //主键 private String name; //姓名 private String job; //工作 private List<Address> addresses; //地址。一个人可能有很多的居住地 /*--它们的setter和getter略--*/ } /** * 上面是演示一对多用到的User实体类 * 下面是演示一对多用到的Address实体类 */ package com.jadyer.model; public class Address { private Integer id; //主键 private Integer userId; //对应User类的id private String address; //地址 private Integer postcode; //邮编 /*--它们的setter和getter略--*/ }
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd"> <sqlMap namespace="User"> <typeAlias alias="user" type="com.jadyer.model.User"/> <typeAlias alias="address" type="com.jadyer.model.Address"/> <resultMap id="get-user-result" class="user"> <result property="id" column="ID"/> <result property="name" column="NAME"/> <result property="job" column="JOB"/> <result property="addresses" column="id" select="User.getAddressesByUserId"/> </resultMap> <select id="getAddressesByUserId" parameterClass="int" resultClass="address"> select address, postcode from t_address where user_id = #userId# </select> <select id="getUsers" resultMap="get-user-result"> select id, name, job from t_user </select> <select id="getUserByName" parameterClass="java.lang.String" resultMap="get-user-result"> select id, name, job from t_user where name = #name# </select> </sqlMap> <!-- 实际开发中,常常遇到关联数据的情况 如User对象拥有若干Address对象,每个Address对象描述了对应User的一个联系地址 此时通常做法是,通过Statement读取用户数据,再手工调用另一个Statement根据用户ID返回对应Address信息 不过这样未免过于繁琐。于是ibatis提供了Statement嵌套支持,通过Statement嵌套,即可实现关联数据的操作 【这里通过在<resultMap/>中定义嵌套查询getAddressByUserId,实现了关联数据的读取】 实际上,这种方式类似于前面所说的通过两条单独的Statement进行关联数据的读取 只是将关联关系在配置中加以描述,由ibatis自动完成关联数据的读取。但,这时就有一个潜在的性能问题,即N+1 所以,在实际的系统设计中,应根据具体情况,采用一些规避手段,如:使用存储过程集中处理大批量关联数据 从而避免因为N+1的问题而导致产品品质上的缺陷 -->
package com.jadyer.test; import java.io.IOException; import java.io.Reader; import java.sql.SQLException; import java.util.List; import org.junit.BeforeClass; import org.junit.Test; import com.ibatis.common.resources.Resources; import com.ibatis.sqlmap.client.SqlMapClient; import com.ibatis.sqlmap.client.SqlMapClientBuilder; import com.jadyer.model.Address; import com.jadyer.model.User; public class IbatisOneToManyTest { private static SqlMapClient sqlMapClient = null; /** * 读取ibatis配置文件,连接数据库,并创建SqlMapClient */ @BeforeClass public static void readConfig() throws IOException { Reader reader = Resources.getResourceAsReader("SqlMapConfig.xml"); sqlMapClient = SqlMapClientBuilder.buildSqlMapClient(reader); reader.close(); } /** * 获取所有用户的,包含了地址的,详细资料 */ @Test public void getUsers() throws SQLException { List<User> userList = sqlMapClient.queryForList("User.getUsers"); for(User user : userList){ System.out.println("==>" + user.getName() + ":" + user.getJob()); for(Address address : user.getAddresses()){ System.out.println(address.getAddress() + "---" +address.getPostcode()); } } } /** * 获取指定用户的,包含了地址的,详细资料 */ @Test public void getUserByName() throws SQLException { User user = (User)sqlMapClient.queryForObject("User.getUserByName", "王怜花"); System.out.println("==>" + user.getName() + ":" + user.getJob()); for(Address address : user.getAddresses()){ System.out.println(address.getAddress() + "---" +address.getPostcode()); } } }
最后是演示一对多映射用到的数据库脚本文件
-- Oracle 11g -- Create table create table t_user( id number, name varchar2(10), job varchar2(20) ); create table t_address( id number, user_id number, address varchar2(20), postcode number ); -- Add data insert into t_user values(1, '沈浪', '侠客'); insert into t_user values(2, '王怜花', '军师'); insert into t_user values(3, '金不换', '财务'); insert into t_address values(1, 1, '来无影去无踪', 999999); insert into t_address values(2, 1, '赏金侠客天君', 888888); insert into t_address values(3, 1, '万剑山庄之主', 777777); insert into t_address values(4, 2, '鬼魅狐影奸狭', 666666); insert into t_address values(5, 2, '易容之术无敌', 555555); insert into t_address values(6, 3, '鬼迷心窍恋财', 444444); insert into t_address values(7, 3, '厚颜无耻杯具', 333333);
下面演示ibatis2.x中的一对一映射
首先是演示一对一映射用到的实体类People.java
package com.jadyer.model; public class People { private Integer id; //主键 private String name; //姓名 private String job; //工作 private String sex; //性别。唯一 private String card; //身份证编号。唯一 /*--它们的setter和getter略--*/ }
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd"> <sqlMap namespace="People"> <typeAlias alias="people" type="com.jadyer.model.People"/> <resultMap id="get-people-result" class="people"> <result property="id" column="ID"/> <result property="name" column="NAME"/> <result property="job" column="JOB"/> <result property="sex" column="SEX"/> <result property="card" column="CARD"/> </resultMap> <select id="getPeoples" resultMap="get-people-result"> select * from t_people, t_identity where t_people.id = t_identity.people_id </select> <select id="getPeopleByName" parameterClass="java.lang.String" resultMap="get-people-result"> select * from t_people, t_identity where name = #name# and t_people.id = t_identity.people_id </select> </sqlMap> <!-- 一对一关联 一对一关联是一对多关联的一种特例。这种情况下,如果一对多的编写方式,将导致1+1条SQL的执行 此时,我们可以采用一次Select两张表的方式,避免这样的性能开销 这时,还应保证People类中包含sex和card两个属性。且此时一个People类就够了,并不需要Identity类 -->
package com.jadyer.test; import java.io.IOException; import java.io.Reader; import java.sql.SQLException; import java.util.List; import org.junit.BeforeClass; import org.junit.Test; import com.ibatis.common.resources.Resources; import com.ibatis.sqlmap.client.SqlMapClient; import com.ibatis.sqlmap.client.SqlMapClientBuilder; import com.jadyer.model.People; public class IbatisOneToOneTest { private static SqlMapClient sqlMapClient = null; /** * 读取ibatis配置文件,连接数据库,并创建SqlMapClient */ @BeforeClass public static void readConfig() throws IOException { Reader reader = Resources.getResourceAsReader("SqlMapConfig.xml"); sqlMapClient = SqlMapClientBuilder.buildSqlMapClient(reader); reader.close(); } /** * 获取所有用户的,包含了身份证的,详细资料 */ @Test public void getPeoples() throws SQLException { List<People> peopleList = sqlMapClient.queryForList("People.getPeoples"); for(People people : peopleList){ System.out.println("==>" + people.getName() + ":" + people.getCard()); } } /** * 获取指定用户的,包含了身份证的,详细资料 */ @Test public void getPeopleByName() throws SQLException { People people = (People)sqlMapClient.queryForObject("People.getPeopleByName", "陈文锦"); System.out.println("==>" + people.getName() + ":" + people.getCard()); } }
最后是演示一对一映射用到的数据库脚本文件
-- Oracle 11g -- Create table create table t_people( id number, name varchar2(8), job varchar2(20) ); create table t_identity( id number, people_id number, sex varchar2(2), card number ); -- Add data insert into t_people values(1, '张起灵', '武器'); insert into t_people values(2, '陈文锦', '领队'); insert into t_people values(3, '吴三省', '插班'); insert into t_identity values(1, 1, '男', 777777777777); insert into t_identity values(2, 2, '女', 666666666666); insert into t_identity values(3, 3, '男', 555555555555);