mybatis环境的搭建以及实现一对多,多对一关联映射
以用户表person和订单表order完成此次搭建
生成数据库的sql语句:
CREATE TABLE person(
personId VARCHAR2(10) PRIMARY KEY,
personName VARCHAR2(20),
personAddress VARCHAR2(50),
personTel VARCHAR2(11)
);
CREATE TABLE orders(
orderId VARCHAR2(36) PRIMARY KEY,
orderNumber VARCHAR2(20),
orderPrice NUMBER,
p_id VARCHAR2(20)
);
INSERT INTO person VALUES('01', 'Linda', 'Shanghai', '1234567');
INSERT INTO orders VALUES('O_00001', '00001', 100, '01');
INSERT INTO orders VALUES('O_00002', '00002', 200, '01');
创建用户和订单的实体类,Person,Order
//Person类
package com.pb.domain;
import java.util.List;
public class Person {
private String personId;
private String personName;
private String address;
private String tel;
private List<Order> orders;//由于是一对多,此处用了集合
//后面是对应属性的setter和getter方法
}
//Order类
package com.pb.domain;
public class Order {
private String orderId;
private String orderNumber;
private int orderPrice;
private Person person;//注意在实体类中是以对象的方式进行关联,这与数据库中以字段方式关联不一样
//后面是对应属性的setter和getter方法
}
配置文件mybatis-cnfig.xml
<!--声明部分以去掉,留下的是核心部分,以下均只留核心部分-->
<configuration>
<properties resource="db.properties"/><!--引入数据库登录信息的资源文件 -->
<typeAliases>
<package name="com.pb.domain"/><!-- 指定包名,此处指定后,映射文件中type类型就无需写类的全限定 -->
</typeAliases>
<!--
development:开发模式
work:工作模式
-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<!-- 设置数据库连接-->
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}" />
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers><!-- 指定映射文件的位置 -->
<mapper resource="com/pb/domain/person.xml"/>
<mapper resource="com/pb/domain/order.xml"/>
</mappers>
</configuration>
映射文件:person.xml和order.xml
<!--order.xml-->
<mapper namespace="domain.order"><!-- namespace只是取一个别名,以便于调用sql时使用 -->
<resultMap type="Order" id="orderResultMap">
<id property="orderId" column="orderId"/>
<result property="orderName" column="orderName"/>
<result property="orderPrice" column="orderPrice"/>
<!-- 方式一:合并型 其中ofType指定students集合中的对象类型 -->
<association property="person" javaType="Person" resultMap="personMap"><!--多对一采取association,一对多采用collection-->
<id property="personId" column="personId"/>
<result property="personName" column="personName"/>
<result property="address" column="personAddress"/>
<result property="tel" column="personTel"/>
</association>
<!-- 方式二,引用方式
<association property="person" resultMap="personMap"/>
-->
</resultMap>
<!-- <resultMap type="Person" id="personMap">
<id property="personId" column="personId"/>
<result property="personName" column="personName"/>
<result property="address" column="personAddress"/>
<result property="tel" column="personTel"/>
</resultMap> -->
<select id="selectOrder" resultMap="orderResultMap" parameterType="String">
select p.*,o.* from person p ,orders o where p.personId = o.p_id and o.p_id like #{p_id}
</select>
</mapper>
<!--person.xml-->
<mapper namespace="domain.person"><!-- namespace只是取一个别名,以便于调用sql时使用 -->
<resultMap type="Person" id="personResultMap">
<id property="personId" column="personId"/>
<result property="personName" column="personName"/>
<result property="address" column="personAddress"/>
<result property="tel" column="personTel"/>
<!-- ofType指定students集合中的对象类型 -->
<collection property="orders" ofType="Order">
<id property="orderId" column="orderId"/>
<result property="orderNumber" column="orderNumber"/>
<result property="orderPrice" column="orderPrice"/>
</collection>
</resultMap>
<select id="selectPerson" resultMap="personResultMap" parameterType="String">
select p.*,o.* from person p ,orders o where p.personId = o.p_id and p.personName like #{personName}
<!--注意要将表关联起来进行查询,不然得不到关联对象,譬如查出了person的personId、personName等普通字段的信息,而orders的信息缺为空,究其原因就是没有进行关联查询-->
</select>
</mapper>
测试类:
public class Test6Test {
public static void main(String[] args) {
/**
* 此处调用了工具类生成SqlSession对象
*/
SqlSession session = MybatisUtil.getSession();
/**
* 测试用户表与订单表的一对多
*/
String seleSql = "domain.person.selectPerson";//一定要注意此处的写法,是映射文件的命名空间加select标签的Id名,中间还有一个点.不能掉
Person person = session.selectOne(seleSql,"_ack%");//传入参数,seleSql参数类似于要执行的sql语句,后面是查询时要传入的参数
System.out.println(person.getPersonName()+"\t"+person.getAddress());
System.out.println(person.getOrders().size());//size()空间不为就说明成功关联了对象
/**
* 测试订单表与用户表的多对一
*/
String seleSql2 = "domain.order.selectOrder";
List<Order> orders = session.selectList(seleSql2, "001");
System.out.println(orders.size());
}
}
工具类:
public class MybatisUtil {
private static SqlSessionFactory factory;
private static Reader reader;
static{
//reader = Resources.getResourceAsReader("mybatis-cfg.xml");
String resource = "mybatis-cfg.xml";
//InputStream is = Test.class.getResourceAsStream(resource);两种方式进行读都可以,InputStream这种方式相对容易想到一点
try {
reader = Resources.getResourceAsReader(resource);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
factory = new SqlSessionFactoryBuilder().build(reader);
}
public static SqlSessionFactory getSessionFactory(){
return factory;
}
public static SqlSession getSession(){
return factory.openSession();
}
public static SqlSession getSession(boolean paramBoolean){
return factory.openSession(true);
}
}
自身总结一下此次搭建过程中比较重要的地方
- 数据库表的设计,关联字段一定得设置正确
- 实体类的属性与数据库表的字段不一致时应如何处理?两种方式,一种在select中的sql语句中实现;二,在resultMap中进行属性与字段的关联。官方推荐的是第二种方式
- 实体类的关联是以对象的形式进行关联,而数据库中的关联是以表的字段进行关联。在xml文件配置时,关联字段的column和实体类关联对象的属性不能列出
- 在实现一对多关联映射的映射文件中,如此例中person.xm,配置关联多那部分对象要用collection标签进行配置。而在实现多对一关联映射文件中,一的那一方要用association标签进行配置
- 实体类的别名在配置文件中以包的路径进行指定,这样处理的好处是包内实体变多时节省了每次书写类的全限定名的时间。
- 映射文件中的命名空间是可以任意设置的,但最好按照末尾包名+配置文件(不要.xml)名方式进行指定,否则可能产生重复的命名空间或者找不到命名空间的状况
- mybatis是支持连续关联映射的。譬如order映射person的同时,还可以在association里面继续进行association映射,只要实体设置恰当以及数据库表之间有相关联的字段,都是可以的