Mybatis基础(二)

关联查询映射

数据库结构

数据库表之间有外键关系的业务关系

(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);
    }
}

猜你喜欢

转载自blog.csdn.net/litianxiang_kaola/article/details/79354081