关联查询映射
数据库结构
数据库表之间有外键关系的业务关系
(1)user和orders
user—->orders:一个用户可以创建多个订单,一对多关系。
orders—->user:一个订单只由一个用户创建,一对一关系。
(2)orders和orderdetail
orders—->orderdetail:一个订单可以包括多个订单明细,因为一个订单可以购买多个商品,每个商品的购买信息在orderdetail记录,一对多关系。
orderdetail—->orders:一个订单明细只能包括在一个订单中,一对一关系。
(3)orderdetail和items:
orderdetail—->items:一个订单明细只对应一个商品信息,一对一关系。
items—->orderdetail:一个商品可以包括在多个订单明细 ,一对多关系。
数据库表之间没有外键关系的业务关系
(1)orders和items
这两张表没有直接的外键关系,通过业务及数据库的间接关系分析出它们是多对多的关系。
orders –>orderdetail –>items:一个订单可以有多个订单明细,一个订单明细对应一个商品,所以一个订单对应多个商品。
items –>orderdetail –>orders:一个商品可以对应多个订单明细,一个订单明细对应一个订单,所以一个商品对应多个订单。
(2)user和items
这两张表没有直接的外键关系,通过业务及数据库的间接关系分析出它们是多对多的关系。
user –>orders –>orderdetail –>items:一个用户有多个订单,一个订单有多个订单明细、一个订单明细对应一个商品,所以一个用户对应多个商品。
items –>orderdetail –>orders –>user:一个商品对应多个订单明细,一个订单明细对应一个订单,一个订单对应一个用户,所以一个商品对应多个用户。
一对一映射
(1)需求
查询订单信息,关联查询创建订单的用户信息。
(2)SQL语句
select
orders.id,
orders.user_id,
orders.number,
orders.createtime,
orders.note,
user.username,
user.address
from orders,user
where orders.user_id = user.id
(3)resultType
复杂查询时,单表对应的POJO类已不能满足输出结果集的映射,所以要根据需求建立一个扩展类来作为resultType的类型。
POJO类
public class OrdersExt extends Orders {
//添加用户属性
private String username;
private String address;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
mapper接口
public interface OrdersMapper {
// 进行订单信息查询,包括用户的名称和地址信息
public List<OrdersExt> findOrdersUser();
}
映射文件
<mapper namespace="org.mapper.OrdersMapper">
<!-- 定义查询订单表列名的SQL片段 -->
<sql id="select_orders">
orders.id,
orders.user_id,
orders.number,
orders.createtime,
orders.note
</sql>
<!-- 定义查询用户表列名的SQL片段 -->
<sql id="select_user">
user.username,
user.address
</sql>
<!-- 进行订单信息查询,包括用户的名称和地址信息 -->
<select id="findOrdersUser" resultType="OrdersExt">
select
<include refid="select_orders" />,
<include refid="select_user"></include>
from orders,user
where orders.user_id = user.id
</select>
</mapper>
加载映射文件
<mappers>
<!-- 批量加载映射文件 -->
<package name="org.mapper" />
</mappers>
测试程序
@Test
public void testFindOrdersUser() {
SqlSession sqlSession = sqlSessionFactory.openSession();
OrdersMapper ordersMapper = sqlSession.getMapper(OrdersMapper.class);
List<OrdersExt> list = ordersMapper.findOrdersUser();
System.out.println(list);
sqlSession.close();
}
(4)resultMap
使用resultMap来进行一对一结果映射,它是将关联对象添加到主信息的对象中,具体说是对象嵌套对象的一种映射方式。
修改POJO类
public class Orders {
private Integer id;
private Integer userId;
private String number;
private Date createtime;
private String note;
//用户信息
private User user;
//getters、setters、toString
}
mapper接口
public interface OrdersMapper {
// 一对一之resultMap
public List<Orders> findOrdersUserRstMap();
}
映射文件
<mapper namespace="org.mapper.OrdersMapper">
<!-- 一对一映射之resultMap -->
<select id="findOrdersUserRstMap" resultMap="OrdersUserRstMap">
select
orders.id,
orders.user_id,
orders.number,
orders.createtime,
orders.note,
user.username,
user.address
from orders,user
where orders.user_id = user.id
</select>
<resultMap type="org.po.Orders" id="OrdersUserRstMap">
<!-- 订单信息 -->
<!-- column="",column的值为上面select语句后面的列名 -->
<id column="id" property="id" />
<result column="user_id" property="userId" />
<result column="number" property="number" />
<result column="createtime" property="createtime" />
<result column="note" property="note" />
<!-- 用户信息(一对一) -->
<!-- association:一对一关联映射 -->
<!-- id标签:指定关联对象结果集的唯一标识,很重要,不写不会报错,但是会影响性能 -->
<!-- property:指定关联对象要映射到Orders的哪个属性上 -->
<association property="user" javaType="org.po.User">
<id column="user_id" property="id" />
<result column="username" property="username" />
<result column="address" property="address" />
</association>
</resultMap>
</mapper>
测试代码
@Test
public void testFindOrdersUserRstMap() {
SqlSession sqlSession = sqlSessionFactory.openSession();
OrdersMapper ordersMapper = sqlSession.getMapper(OrdersMapper.class);
List<Orders> list = ordersMapper.findOrdersUserRstMap();
System.out.println(list);
sqlSession.close();
}
(5)小结
在一对一结果映射时,使用resultType更加简单方便,如果有特殊要求(对象嵌套对象)时,需要使用resultMap进行映射,比如:查询订单列表,然后在点击列表中的查看订单明细按钮,这个时候就需要使用resultMap进行结果映射。而resultType更适应于查询明细信息,比如,查询订单明细列表。
一对多映射
(1)需求
查询订单信息,关联查询订单明细信息及用户信息。
(2)SQL语句
select
orders.id,
orders.user_id,
orders.number,
orders.createtime,
orders.note,
user.username,
user.address,
orderdetail.id detail_id,
orderdetail.items_id,
orderdetail.items_num
from orders,user,orderdetail
where orders.user_id = user.id
and orders.id = orderdetail.orders_id
(3)POJO类
public class Orders {
private Integer id;
private Integer userId;
private String number;
private Date createtime;
private String note;
//用户信息(一对一)
private User user;
//订单明细(一对多)
private List<Orderdetail> detailList;
//getters、setters、toString
}
(4)mapper接口
public interface OrdersMapper {
// 一对多之resultMap
public List<Orders> findOrdersAndOrderdetailRstMap();
}
(5)映射文件
<mapper namespace="org.mapper.OrdersMapper">
<!-- 一对多映射 -->
<select id="findOrdersAndOrderdetailRstMap" resultMap="OrdersAndOrderdetailRstMap">
select
orders.id,
orders.user_id,
orders.number,
orders.createtime,
orders.note,
user.username,
user.address,
orderdetail.id detail_id,
orderdetail.items_id,
orderdetail.items_num
from orders,user,orderdetail
where orders.user_id = user.id
and orders.id = orderdetail.orders_id
</select>
<!-- 定义OrdersAndOrderdetailRstMap -->
<!-- extends:继承已有的ResultMap,注意它继承的resultMap的type和它本身的type要保持一致-->
<resultMap type="Orders" id="OrdersAndOrderdetailRstMap"
extends="OrdersUserRstMap">
<!-- 映射关联关系(一对多) -->
<!-- collection标签:定义一个一对多关系-->
<!-- ofType:指定该集合参数所映射的类型 -->
<!-- column="",column的值为上面select语句后面的列名 -->
<collection property="detailList" ofType="Orderdetail">
<id column="detail_id" property="id" />
<result column="items_id" property="itemsId" />
<result column="items_num" property="itemsNum" />
</collection>
</resultMap>
<resultMap type="org.po.Orders" id="OrdersUserRstMap">
<id column="id" property="id" />
<result column="user_id" property="userId" />
<result column="number" property="number" />
<result column="createtime" property="createtime" />
<result column="note" property="note" />
<association property="user" javaType="org.po.User">
<id column="user_id" property="id" />
<result column="username" property="username" />
<result column="address" property="address" />
</association>
</resultMap>
</mapper>
(6)测试代码
@Test
public void testFindOrdersAndOrderdetailRstMap() {
SqlSession sqlSession = sqlSessionFactory.openSession();
OrdersMapper ordersMapper = sqlSession.getMapper(OrdersMapper.class);
List<Orders> list = ordersMapper.findOrdersAndOrderdetailRstMap();
System.out.println(list);
sqlSession.close();
}
(7)小结
Mybatis使用resultMap的collection对关联查询的多条记录映射到一个list集合属性中。
使用resultType实现,需要对结果集进行二次处理,使用双重循环遍历,去掉重复记录,将订单明细放在orderdetails中。
多对多映射
(1)需求
查询用户信息,关联查询该用户购买的商品信息。
(2)SQL语句
select
orders.id,
orders.user_id,
orders.number,
orders.createtime,
orders.note,
user.username,
user.address,
orderdetail.id detail_id,
orderdetail.items_id,
orderdetail.items_num,
items.name items_name,
items.detail items_detail
FROM
orders,
user,
orderdetail,
items
WHERE user.id = orders.user_id
AND orders.id = orderdetail.orders_id
AND orderdetail.items_id = items.id
(3)映射思路
- 将用户信息映射到user中。
- 在user类中添加订单列表属性List orderslist,将用户创建的订单映射到orderslist。
- 在Orders中添加订单明细列表属性List detailList,将订单的明细映射到detailList。
- 在Orderdetail中添加Items属性,将订单明细所对应的商品映射到Items。
(4)POJO类
public class User {
private int id;
private String username;
private String sex;
private Date birthday;
private String address;
// 订单信息
private List<Orders> ordersList;
//getters、setters、toString
}
public class Orders {
private Integer id;
private Integer userId;
private String number;
private Date createtime;
private String note;
//订单明细(一对多)
private List<Orderdetail> detailList;
}
public class Orderdetail {
private Integer id;
private Integer ordersId;
private Integer itemsId;
private Integer itemsNum;
//商品信息
private Items items;
}
(5)mapper接口
public interface OrdersMapper {
// 多对多之resultMap
public List<User> findUserAndItemsRstMap();
}
(6)映射文件
<mapper namespace="org.mapper.OrdersMapper">
<!-- 多对多映射之使用resultMap -->
<select id="findUserAndItemsRstMap" resultMap="UserAndItemsRstMap">
select
orders.id,
orders.user_id,
orders.number,
orders.createtime,
orders.note,
user.username,
user.address,
orderdetail.id detail_id,
orderdetail.items_id,
orderdetail.items_num,
items.name items_name,
items.detail items_detail
FROM
orders,
user,
orderdetail,
items
WHERE user.id = orders.user_id
AND orders.id = orderdetail.orders_id
AND orderdetail.items_id = items.id
</select>
<!-- 定义UserAndItemsRstMap -->
<resultMap type="User" id="UserAndItemsRstMap">
<!-- 用户信息 -->
<!-- id:关联查询用户的唯一标示 -->
<!-- column="",column的值为上面select语句后面的列名 -->
<id column="user_id" property="id" />
<result column="username" property="username" />
<result column="address" property="address" />
<!-- 订单信息 (一个用户有多个订单) -->
<collection property="ordersList" ofType="orders">
<id column="id" property="id" />
<result column="user_id" property="userId" />
<result column="number" property="number" />
<result column="createtime" property="createtime" />
<result column="note" property="note" />
<!-- 订单明细信息(一个订单有多个订单明细) -->
<collection property="detailList" ofType="orderdetail">
<id column="detail_id" property="id" />
<result column="items_id" property="itemsId" />
<result column="items_num" property="itemsNum" />
<!-- 商品信息 (一个订单明细对应一个商品) -->
<association property="items" javaType="org.po.Items">
<id column="items_id" property="id" />
<result column="items_name" property="name" />
<result column="items_detail" property="detail" />
</association>
</collection>
</collection>
</resultMap>
</mapper>
(7)测试代码
@Test
public void testFindUserAndItemsRstMap() {
SqlSession sqlSession = sqlSessionFactory.openSession();
OrdersMapper ordersMapper = sqlSession.getMapper(OrdersMapper.class);
List<User> list = ordersMapper.findUserAndItemsRstMap();
System.out.println(list);
sqlSession.close();
}
延迟加载
什么是延迟加载?
延迟加载的意思是说,在关联查询时,利用延迟加载,先加载主信息。需要关联信息时再去按需加载关联信息。这样会大大提高数据库性能,因为查询单表要比关联查询多张表速度要快。resultMap中的association和collection标签具有延迟加载的功能。
设置延迟加载
Mybatis默认是不开启延迟加载功能的,我们需要手动开启。在SqlMapConfig.xml文件中,在标签中开启延迟加载功能。
使用association进行延迟加载
(1)需求
查询订单并且关联查询用户信息(对用户信息的加载要求是按需加载)。
(2)SqlMapConfig.xml 配置文件
<settings>
<!-- lazyLoadingEnabled:延迟加载启用(懒加载),默认是false -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- aggressiveLazyLoading:积极的懒加载,false表示按需加载。默认是true -->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
(3)映射文件
<mapper namespace="org.mapper.OrdersMapper">
<!-- 定义OrdersUserLazyLoadingRstMap -->
<resultMap type="org.po.Orders" id="OrdersUserLazyLoadingRstMap">
<id column="id" property="id" />
<result column="user_id" property="userId" />
<result column="number" property="number" />
<result column="createtime" property="createtime" />
<result column="note" property="note" />
<!-- 延迟加载用户信息 -->
<!-- select:指定延迟加载需要执行的statement的id-->
<!-- column:主信息表中需要关联查询的列,此处是user_id -->
<association property="user" select="org.mapper.UserMapper.findUserById" column="user_id"></association>
</resultMap>
<!-- 查询订单信息,延迟加载关联查询的用户信息 -->
<select id="findOrdersUserLazyLoading" resultMap="OrdersUserLazyLoadingRstMap">
SELECT * FROM orders
</select>
</mapper>
<mapper namespace="org.mapper.UserMapper">
<!-- 查询用户信息 -->
<select id="findUserById" parameterType="int" resultType="org.po.User">
SELECT * FROM user WHERE id = #{id}
</select>
</mapper>
(4)mapper接口
public interface OrdersMapper {
// 延迟加载
public List<Orders> findOrdersUserLazyLoading();
}
(5)测试代码
@Test
public void testFindOrdersUserLazyLoading() {
SqlSession sqlSession = sqlSessionFactory.openSession();
OrdersMapper ordersMapper = sqlSession.getMapper(OrdersMapper.class);
List<Orders> list = ordersMapper.findOrdersUserLazyLoading();
//当没有下面这条语句时,只查询orders,否则查询orders和user
System.out.println(list);
sqlSession.close();
}
延迟加载思考
不使用Mybatis提供的association及collection中的延迟加载功能,如何实现延迟加载?
(1)定义两个mapper方法
- 查询订单列表
- 根据用户id查询用户信息
(2)实现思路
先去查询第一个mapper方法,获取订单信息列表,在程序中(service),按需去调用第二个mapper方法去查询用户信息。
查询缓存
Mybatis提供查询缓存,如果缓存中有数据就不用从数据库中获取,用于减轻数据压力,提高系统性能。
一级缓存是SqlSession级别的缓存。在操作数据库时需要构造 sqlSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据。不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的。
二级缓存是mapper级别的缓存。多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession可以共用二级缓存。二级缓存是跨SqlSession的。
一级缓存默认使用,二级缓存需要手动开启。
一级缓存
(1)原理
第一次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,如果没有,从数据库查询用户信息。得到用户信息,将用户信息存储到一级缓存中。
如果sqlSession去执行commit操作(执行插入、更新、删除),清空SqlSession中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。
第二次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,缓存中有,直接从缓存中获取用户信息。
(2)测试
@Test
public void testOneLevelCache() {
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 第一次查询ID为1的用户,去缓存找,找不到就去查找数据库
User user1 = mapper.findUserById(1);
System.out.println(user1);
// 第二次查询ID为1的用户
User user2 = mapper.findUserById(1);
System.out.println(user2);
sqlSession.close();
}
只输出一次SQL:
@Test
public void testOneLevelCache() {
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 第一次查询ID为1的用户,去缓存找,找不到就去查找数据库
User user1 = mapper.findUserById(1);
System.out.println(user1);
User user = new User();
user.setUsername("弗兰克");
user.setAddress("查令街84号");
//执行增删改操作,清空缓存
mapper.insertUser(user);
// 第二次查询ID为1的用户
User user2 = mapper.findUserById(1);
System.out.println(user2);
sqlSession.close();
}
中间执行了commit操作,同样的查询SQL输出两次:
二级缓存
(1)原理
第一次调用mapper下的SQL去查询用户信息。查询到的信息会存到该mapper对应的二级缓存区域内。
第二次调用相同namespace下的mapper映射文件中相同的SQL去查询用户信息,会到对应的二级缓存内取结果。
如果调用相同namespace下的mapper映射文件中的增删改SQL,并执行了commit操作。此时会清空该namespace下的二级缓存。
(2)开启二级缓存
在 SqlMapConfig.xml 中开启二级缓存
<settings>
<!-- 开启二级缓存总开关 -->
<setting name="cacheEnabled" value="true"/>
</settings>
在映射文件中开启二级缓存
<!-- 开启本mapper下的namespace的二级缓存,默认使用的是Mybatis提供的PerpetualCache -->
<cache></cache>
实现序列化
public class User implements Serializable{
private int id;
private String username;
private String sex;
private Date birthday;
private String address;
//getters、setters、toString
}
由于二级缓存的数据不一定都是存储到内存中,它的存储介质多种多样,所以需要给缓存的对象执行序列化。如果该类存在父类,那么父类也要实现序列化。
(3)测试
@Test
public void testTwoLevelCache() {
SqlSession sqlSession1 = sqlSessionFactory.openSession();
SqlSession sqlSession2 = sqlSessionFactory.openSession();
SqlSession sqlSession3 = sqlSessionFactory.openSession();
UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
UserMapper mapper3 = sqlSession3.getMapper(UserMapper.class);
// 第一次查询ID为1的用户,去缓存找,找不到就去查找数据库
User user1 = mapper1.findUserById(1);
System.out.println(user1);
sqlSession1.close();
// 第二次查询ID为1的用户
User user2 = mapper2.findUserById(1);
System.out.println(user2);
sqlSession2.close();
}
只查询了一次数据库。
@Test
public void testTwoLevelCache() {
SqlSession sqlSession1 = sqlSessionFactory.openSession();
SqlSession sqlSession2 = sqlSessionFactory.openSession();
SqlSession sqlSession3 = sqlSessionFactory.openSession();
UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
UserMapper mapper3 = sqlSession3.getMapper(UserMapper.class);
// 第一次查询ID为1的用户,去缓存找,找不到就去查找数据库
User user1 = mapper1.findUserById(1);
System.out.println(user1);
sqlSession1.close();
//修改查询出来的user1对象,作为插入语句的参数
user1.setUsername("弗兰克");
user1.setAddress("查令街84号");
mapper3.insertUser(user1);
sqlSession3.commit();
sqlSession3.close();
// 第二次查询ID为1的用户
User user2 = mapper2.findUserById(1);
System.out.println(user2);
sqlSession2.close();
}
根据SQL分析,确实是清空了二级缓存。
(3)禁用二级缓存
在statement中设置userCache=false,可以禁用当前select语句的二级缓存,即每次查询都是去数据库中查询,默认情况下是true,即该statement使用二级缓存。
<select id="findUserById" parameterType="int" resultType="org.po.User" useCache="false">
SELECT * FROM user WHERE id = #{id}
</select>
(4)刷新二级缓存
在statement中设置 flushCache=true 可以刷新当前的二级缓存,默认情况下如果是select语句,那么flushCache是false。如果是insert、update、delete语句,那么flushCache是true。
如果查询语句设置成true,那么每次查询都是去数据库查询,即意味着该查询的二级缓存失效。
如果查询语句设置成false,即使用二级缓存,那么如果在数据库中修改了数据,而缓存数据还是原来的,这个时候就会出现脏读。
<select id="findUserById" parameterType="int" resultType="org.po.User" useCache="true" flushCache="false">
SELECT * FROM user WHERE id = #{id}
</select>
Mybatis整合Spring
集成思路
- 需要Spring来管理数据源信息。
- 需要Spring通过单例方式管理SqlSessionFactory。
- 使用SqlSessionFactory创建SqlSession。(Spring和Mybatis整合自动完成)
- 持久层的mapper都需要由Spring进行管理,Spring和Mybatis整合生成mapper代理对象。
原始dao开发方式
(1)映射文件User.xml
<mapper namespace="test">
<!-- 根据用户ID查询用户信息 -->
<select id="findUserById" parameterType="int" resultType="user">
SELECT
* FROM USER WHERE id =#{id}
</select>
</mapper>
(2)dao代码
public interface UserDao {
// 根据用户ID查询用户信息
public User findUserById(int id) throws Exception;
}
public class UserDaoImpl extends SqlSessionDaoSupport implements UserDao {
public User findUserById(int id) throws Exception {
return this.getSqlSession().selectOne("test.findUserById", id);
}
}
(3)SqlMapConfig.xml
<configuration>
<!-- 自定义别名 -->
<typeAliases>
<package name="org.po" />
</typeAliases>
<!-- 加载映射文件 -->
<mappers>
<mapper resource="mybatis/sqlmap/User.xml" />
</mappers>
</configuration>
(4)applicationContext.xml
<beans>
<!-- 加载配置文件 -->
<context:property-placeholder location="db.properties" />
<!-- 创建数据源 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${db.driver}" />
<property name="url" value="${db.url}" />
<property name="username" value="${db.username}" />
<property name="password" value="${db.password}" />
<property name="maxActive" value="10" />
<property name="maxIdle" value="5" />
</bean>
<!-- SqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 指定mybatis的全局配置文件的路径 -->
<property name="configLocation" value="mybatis/SqlMapConfig.xml"></property>
<!-- 数据源 -->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- UserDao -->
<bean id="userDao" class="org.dao.UserDaoImpl">
<!-- 依赖注入SqlSessionFactory -->
<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean>
</beans>
(5)测试代码
public class UserDaoTest {
private ApplicationContext ctx;
@Before
public void setUp() throws Exception {
ctx = new ClassPathXmlApplicationContext(
"spring/applicationContext.xml");
}
@Test
public void testFindUserById() throws Exception {
// 创建UserDao
UserDao dao = (UserDao) ctx.getBean("userDao");
User user = dao.findUserById(1);
System.out.println(user);
}
}
Mapper代理
(1)映射文件UserMapper.xml
<mapper namespace="org.mapper.UserMapper">
<!-- 根据用户ID查询用户信息 -->
<select id="findUserById" parameterType="int" resultType="User">
SELECT
* FROM USER WHERE id =#{id}
</select>
</mapper>
(2)Mapper接口
public interface UserMapper {
// 根据用户ID查询用户信息
public User findUserById(int id) ;
}
(3)SqlMapConfig.xml
<configuration>
<!-- 自定义别名 -->
<typeAliases>
<package name="org.po" />
</typeAliases>
</configuration>
(4)applicationContext.xml
<beans>
<!-- 加载配置文件 -->
<context:property-placeholder location="db.properties" />
<!-- 创建数据源 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${db.driver}" />
<property name="url" value="${db.url}" />
<property name="username" value="${db.username}" />
<property name="password" value="${db.password}" />
<property name="maxActive" value="10" />
<property name="maxIdle" value="5" />
</bean>
<!-- SqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 指定mybatis的全局配置文件的路径 -->
<property name="configLocation" value="mybatis/SqlMapConfig.xml"></property>
<!-- 数据源 -->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 单个Mapper代理类配置 -->
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<!-- 设置代理类的接口 -->
<property name="mapperInterface" value="org.mapper.UserMapper"></property>
<!-- 依赖注入SqlSessionFactory -->
<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean>
<!-- 批量配置Mapper代理类,默认bean的id为类名首字母小写 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 配置扫描的包 -->
<property name="basePackage" value="org.mapper"></property>
<!-- 默认不需要配置SqlSessionFactory(只有一个SqlSessionFactory时),单独配置也可以 -->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
</bean>
</beans>
(5)测试代码
public class UserMapperTest {
private ApplicationContext ctx;
@Before
public void setUp() throws Exception {
ctx = new ClassPathXmlApplicationContext(
"spring/applicationContext.xml");
}
@Test
public void testFindUserById() {
UserMapper mapper = (UserMapper) ctx.getBean("userMapper");
User user = mapper.findUserById(1);
System.out.println(user);
}
}