JavaEE程序设计【十】

9、关联映射

MyBatis(五):mybatis关联映射

Mybatis关联映射

(1)一对一

在Mapper文件的<resultMap>元素中,包含了一个<association>子元素,MyBatis就是通过该元素来处理一对一关联关系的。

  • property:指定映射到的实体类对象属性,与表字段一一对应
  • column:指定表中对应的字段
  • javaType:指定映射到实体对象属性的类型
  • select:指定引入嵌套查询的子SQL语句,该属性用于关联映射中的嵌套查询
  • fetchType:指定在关联查询时是否启用延迟加载。该属性有lazy和eager两个属性值,默认值为lazy(即默认关联映射延迟加载)

MyBatis加载关联关系对象主要通过两种方式:嵌套查询和嵌套结果。

嵌套查询的方式要执行多条SQL语句,这对于大型数据集合和列表展示不是很好,因为这样可能会导致成百上千条关联的SQL语句被执行,从而极大的消耗数据库性能并且会降低查询效率。

MyBatis延迟加载的配置

使用MyBatis的延迟加载在一定程度上可以降低运行消耗并提高查询效率。MyBatis默认没有开启延迟加载,需要在核心配置文件中的<settings>元素内进行配置,具体配置方式如下:

1
2
3
4
5
6
<settings>
<setting name="lazyLoadingEnabled" value="true" />
<!-- 打开延迟加载的开关 -->
<setting name="aggressiveLazyLoading" value="false"/>
<!-- 将积极加载改为消息加载,即按需加载 -->
</settings>

不论默认值是什么,进行显性表示,防止版本更新带来默认值变化等。

在映射文件中,<association>元素和<collection>元素中都已默认配置了延迟加载属性,即默认属性fetchType=”lazy”(属性fetchType=”eager”表示立即加载),所以在配置文件中开启延迟加载后,无需在映射文件中再做配置。,但是若全局配置懒加载想要在某个方法中关闭懒加载可以配置fetchType。

方法1:嵌套查询

PersonMapper.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<select id="selectByPrimaryKey"
parameterType="java.lang.Integer" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from person
where id = #{id,jdbcType=INTEGER}
</select>

<resultMap id="BaseResultMap"
type="cn.edu.ccc.ch9.dao.Person">
<id column="id" jdbcType="INTEGER" property="id" />
<result column="name" jdbcType="VARCHAR" property="name" />
<result column="age" jdbcType="INTEGER" property="age" />
<result column="card_id" jdbcType="INTEGER" property="cardId" />
<association property="card" column="card_id"
javaType="cn.edu.ccc.ch9.dao.IdCard"
select="cn.edu.ccc.ch9.dao.IdCardMapper.selectByPrimaryKey">
</association>
</resultMap>

IdCardMapper.xml

1
2
3
4
5
6
<select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from idcard
where id = #{id,jdbcType=INTEGER}
</select>

==指的是将column中的对应表字段作为参数传入到Select中的查询语句,将查询结果传入property表示的类中的属性中==

==若传入多个参数,可使用column=”card_id”==

方法2:嵌套结果

PersonMapper.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
	<select id="selectByPrimaryKey2"
parameterType="java.lang.Integer" resultMap="BaseResultMap2">
select
p.*,idcard.code
from person p,idcard idcard
where p.card_id=idcard.id
and p.id=#{id}
</select>
<resultMap id="BaseResultMap2"
type="cn.edu.ccc.ch9.dao.Person">
<id column="id" jdbcType="INTEGER" property="id" />
<result column="name" jdbcType="VARCHAR" property="name" />
<result column="age" jdbcType="INTEGER" property="age" />
<result column="card_id" jdbcType="INTEGER" property="cardId" />
<association property="card"
javaType="cn.edu.ccc.ch9.dao.IdCard">
<id column="id" property="id"/>
<result column="code" property="code"/>
</association>
</resultMap>

mybatis 嵌套查询子查询column传多个参数描述

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
> <resultMap id="blogResult" type="Blog">
>
> <association property="author" column="{id=author_id,likename=author_name}" javaType="Author" select="selectAuthor"/>
>
> </resultMap>
>
>
>
> <select id="selectBlog" resultMap="blogResult" parameterType="java.lang.String">
>
> SELECT author_id,author_name FROM BLOG WHERE ID = #{id}
>
> </select>
>
>
>
> <select id="selectAuthor" resultType="Author" parameterType="java.util.HashMap">
>
> SELECT * FROM AUTHOR WHERE 1=1
>
> <if test="id != null and id != '' ">
>
> and ID = #{id}
>
> </if>
>
> <if test="likename != null and likename != '' ">
>
> and name like CONCAT('%',#{likename},'%')
>
> </if>
>
> </select>
>

==嵌套查询:方法—>映射SQL语句—>结果集—>映射SQL语句—>结果集==

==嵌套结果:方法—>映射SQL语句—>结果集==

(2)一对多

在Mapper文件的<resultMap>元素中,包含了一个<collection>子元素,MyBatis就是通过该元素来处理一对多关联关系的。

<collection>子元素的属性大部分与<association>元素相同,但其还包含一个特殊属性——ofType.

ofType属性与javaType属性对应,它用于指定实体对象中集合类属性所包含的元素类型。

方法1:嵌套查询

UserMapper.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<select id="selectByPrimaryKey"
parameterType="java.lang.Integer" resultMap="BaseResultMap2">
select
<include refid="Base_Column_List" />
from user
where id = #{id,jdbcType=INTEGER}
</select>

<resultMap id="BaseResultMap2" type="cn.edu.ccc.ch9.dao.User">
<id column="id" jdbcType="INTEGER" property="id" />
<result column="name" jdbcType="VARCHAR" property="name" />
<result column="password" jdbcType="VARCHAR"
property="password" />
<collection property="orderlist" column="id"
ofType="cn.edu.ccc.ch9.Orders"
select="cn.edu.ccc.ch9.dao.OrdersMapper.selectByUserid"></collection>
</resultMap>

OrdersMapper.xml

1
2
3
4
5
6
<select id="selectByUserid" parameterType="java.lang.Integer" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from orders
where user_id = #{id,jdbcType=INTEGER}
</select>

方法2:嵌套结果

UserMapper.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<resultMap id="BaseResultMap3" type="cn.edu.CCC.ch9.dao.User">
<id column="id" jdbcType="INTEGER" property="id" />
<result column="name" jdbcType="VARCHAR" property="name" />
<result column="password" jdbcType="VARCHAR"
property="password" />
<collection property="orderList"
ofType="cn.edu.CCC.ch9.dao.Orders">
<id column="id" jdbcType="INTEGER" property="id" />
<result column="number" jdbcType="VARCHAR" property="number" />
<result column="user_id" jdbcType="INTEGER" property="userId" />
</collection>
</resultMap>

<select id="selectByPrimaryKey3"
parameterType="java.lang.Integer" resultMap="BaseResultMap3">
select
user.id, name, password,number
from user,orders
where user.id = #{id,jdbcType=INTEGER} and user_id=user.id
</select>

一般来说,运行正常,但是查询不出结果,大多数是SQL语句有错误,常常为多表中的字段只用简写产生歧义。例如user中的id和orders中的id。若不该为user.id和orders.id,是查不出来的。尤其是使用sql标签把查询的参数抽取出来的时候更容易出这样的错误

(3)多对多

在数据库中,多对多的关联关系通常使用一个中间表来维护,中间表中的订单id作为外键参照订单表的id,商品id作为外键参照商品表的id。

多对多本质上就是两个一对多的设计

10、mybatis和spring的整合

Mybatis(六) Spring整合mybatis

mybatis-spring官方中文文档

先回顾一下mybatis最基础的根基:

mybatis,有两个配置文件

全局配置文件SqlMapConfig.xml(配置数据源,全局变量,加载映射文件等东西)

映射文件xxxMapper.xml,用来对输入参数输出参数,数据库语句做配置的。

mybatis配置好之后的使用步骤

1、获取sqlMapConfig.xml的位置然后进行加载

2、通过sqlMapConfig.xml中的内容创建出sqlsessionFactory对象

3、然后通过sqlsessionFactory对象创建出sqlsession对象

4、有了sqlsession对象就可以进行相应的操作了。

集成思路

有了上面的一些知识回顾,那么就有思路让spring继承mabatis了。

1、让spring来管理数据源信息,sqlMapConfig.xml中就不需要加载数据源了。交给spring管理

2、让spring通过单例方式管理SqlSessionFactory,只需要一个SqlSessionFactory帮我们生成sqlsession即可。也就是需要sqlsession对象就让sqlsessionfactory生成。所以是单例方式。

3、让spring创建sqlsession bean。也就是通过SqlSessionFactory创建SqlSession,

4、如果是使用mapper代理开发的方式,那么持久层的mapper都需要由spring进行管理,spring和mybatis整合生成mapper代理对象。

(1)环境准备

  • Spring框架所需的JAR包

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    /*AOP开发使用的JAR*/
    aopalliance-1.0.jar
    aspectjweaver-1.8.10.jar
    spring-aop-4.3.6.RELEASE.jar
    spring-aspects-4.3.6.RELEASE.jar
    /*4个核心模块JAR*/
    spring-beans-4.3.6.RELEASE.jar
    spring-context-4.3.6.RELEASE.jar
    spring-core-4.3.6.RELEASE.jar
    spring-expression-4.3.6.RELEASE.jar
    /*JDBC和事务的JAR*/
    spring-jdbc-4.3.6.RELEASE.jar
    spring-tx-4.3.6.RELEASE.jar
    • 注:核心容器依赖的commons-logging的JAR在MyBatis框架的lib包中已经包含!
  • MyBatis框架所需的JAR包

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    ant-1.9.6.jar
    ant-launcher-1.9.6.jar
    asm-5.1.jar
    cglib-3.2.4.jar
    commons-logging-1.2.jar
    javassist-3.21.0-GA.jar
    log4j-1.2.17.jar
    log4j-api-2.3.jar
    log4j-core-2.3.jar
    mybatis-3.4.2.jar
    ognl-3.1.12.jar
    slf4j-api-1.7.22.jar
    slf4j-log4j12-1.7.22.jar
  • MyBatis与Spring整合的中间JAR

    1
    mybatis-spring-1.3.1.jar
  • 数据库驱动JAR(MySQL)

    1
    mysql-connector-java-5.1.40-bin.jar
  • 数据源所需JAR(DBCP)

    1
    2
    commons-dbcp2-2.1.1.jar
    commons-pool2-2.4.2.jar

==若使用MAVEN添加依赖:==

注:提取properties方便修改版本。尤其是Spring相关,多个依赖的版本控制都是spring.version

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
<junit.version>4.12</junit.version>
<spring.version>5.2.5.RELEASE</spring.version>
<mybatis.version>3.5.4</mybatis.version>
<mybatis.spring.version>2.0.4</mybatis.spring.version>
<mysql.version>5.1.48</mysql.version>
<commons-dbcp.version>2.7.0</commons-dbcp.version>
</properties>

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>${mybatis.spring.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>${commons-dbcp.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.4.0</version>
</dependency>
</dependencies>

(2)Dao方式使用

采用传统DAO开发方式进行MyBatis与Spring框架的整合时,可以使用mybatis-spring包中所提供的SqlSessionTemplate类或SqlSessionDaoSupport类来实现。

  • SqlSessionTemplate:是mybatis-spring的核心类,它负责管理MyBatis的SqlSession,调用MyBatis的SQL方法。当调用SQL方法时,SqlSessionTemplate将会保证使用的SqlSession和当前Spring的事务是相关的。它还管理SqlSession的生命周期,包含必要的关闭、提交和回滚操作。
  • SqlSessionDaoSupport:是一个抽象支持类,它继承了DaoSupport类,主要是作为DAO的基类来使用。可以通过SqlSessionDaoSupport类的getSqlSession()方法来获取所需的SqlSession。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Repository
public class CustomerDaoImpl extends SqlSessionDaoSupport implements ICustomerDao {
@Autowired
public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
super.setSqlSessionFactory(sqlSessionFactory);
}
public void add(Customer cc) {
CustomerMapper customerMapper = this.getSqlSession().getMapper(CustomerMapper.class);
int count = customerMapper.insert(cc);
System.out.println("添加了" + count + "行数据。");

int update = this.getSqlSession().update("cn.edu.ccc.ch10.dao.CustomerMapper.insert", cc);
System.out.println("--添加了"+update);
}}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:spring-mybatis.xml")
public class CustomerDaoTest {
@Autowired
private ICustomerDao customerDaoImpl;
@Test
public void addTest() {
Customer cc = new Customer();
cc.setUsername("AAA");
……
customerDaoImpl.add(cc);
System.out.println("添加成功");
}
}

(3)mybatis-spring整合映射文件方式使用

①SqlSessionFactoryBean

在基础的 MyBatis 用法中,是通过 SqlSessionFactoryBuilder 来创建 SqlSessionFactory 的。 而在 MyBatis-Spring 中,则使用 SqlSessionFactoryBean 来创建。

要创建工厂 bean,将下面的代码放到 Spring 的 XML 配置文件中:

1
2
3
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
</bean>

需要注意的是 SqlSessionFactoryBean 实现了 Spring 的 FactoryBean 接口(参见 Spring 官方文档 3.8 节 通过工厂 bean 自定义实例化逻辑)。==这意味着由 Spring 最终创建的 bean 并不是 SqlSessionFactoryBean 本身,而是工厂类(SqlSessionFactoryBean)的 getObject() 方法的返回结果。(和Spring的手动配置工厂来进行装配相关,这种模式日常中我们开发用得少)==这种情况下,Spring 将会在应用启动时为你创建 SqlSessionFactory,并使用 sqlSessionFactory 这个名字存储起来。

MyBatis中SqlSessionFactoryBean的作用

为什么返回的是SqlSessionFactory对象而不是SqlSessionFactoryBean
首先spring在初始化的时候会将所有创建的单例以Map<K,V>的形式放入singletonObjects,同时调用FactoryBean的getObject()将返回的对象以Map<K,V>的形式放入factoryBeanObjectCache

如{sqlSessionFactory=org.apache.ibatis.session.defaults.DefaultSqlSessionFactory@d997f9}

然后getBean的时候,spring利用getSingleton从singletonObjects获取单例(这里是SqlSessionFactoryBean对象),判断是否实现了FactoryBean接口,若实现了就从factoryBeanObjectCache利用beanname(这里是sqlSessionFactory)重新获取,若未实现则返回getSingleton获取的单例

等效的 Java 代码如下:

1
2
3
4
5
6
@Bean
public SqlSessionFactory sqlSessionFactory() {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource());
return factoryBean.getObject();
}

通常,在 MyBatis-Spring 中,你不需要直接使用 SqlSessionFactoryBean 或对应的 SqlSessionFactory。相反,session 的工厂 bean 将会被注入到 MapperFactoryBean 或其它继承于 SqlSessionDaoSupport 的 DAO(Data Access Object,数据访问对象)中。

SqlSessionFactory 有一个唯一的必要属性:用于 JDBC 的 DataSource。这可以是任意的 DataSource 对象,它的配置方法和其它 Spring 数据库连接是一样的。

一个常用的属性是 configLocation,它用来指定 MyBatis 的 XML 配置文件路径。它在需要修改 MyBatis 的基础配置非常有用。通常,基础配置指的是 <settings><typeAliases> 元素。

需要注意的是,这个配置文件并不需要是一个完整的 MyBatis 配置。确切地说,任何环境配置(<environments>),数据源(<DataSource>)和 MyBatis 的事务管理器(<transactionManager>)都会被忽略SqlSessionFactoryBean 会创建它自有的 MyBatis 环境配置(Environment),并按要求设置自定义环境的值。

如果 MyBatis 在映射器类对应的路径下找不到与之相对应的映射器 XML 文件,那么也需要配置文件。这时有两种解决办法:第一种是手动在 MyBatis 的 XML 配置文件中的<mappers> 部分中指定 XML 文件的类路径;第二种是设置工厂 bean 的 mapperLocations 属性。

mapperLocations 属性接受多个资源位置。这个属性可以用来指定 MyBatis 的映射器 XML 配置文件的位置。属性的值是一个 Ant 风格的字符串,可以指定加载一个目录中的所有文件,或者从一个目录开始递归搜索所有目录。比如:

1
2
3
4
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mapperLocations" value="classpath*:sample/config/mappers/**/*.xml" />
</bean>

这会从类路径下加载所有在 sample.config.mappers 包和它的子包中的 MyBatis 映射器 XML 配置文件。

其他再查阅官方文档:https://mybatis.org/spring/zh/factorybean.html

在 MyBatis 中,你可以使用 SqlSessionFactory 来创建 SqlSession。一旦你获得一个 session 之后,你可以使用它来执行映射了的语句,提交或回滚连接,最后,当不再需要它的时候,你可以关闭 session。使用 MyBatis-Spring 之后,你不再需要直接使用 SqlSessionFactory 了,因为你的 bean 可以被注入一个线程安全的 SqlSession,它能基于 Spring 的事务配置来自动提交、回滚、关闭 session。

②手动配置MapperFactoryBean方式(麻烦,很少用)

MapperFactoryBean是MyBatis-Spring团队提供的一个用于根据Mapper接口生成Mapper对象的类,该类在Spring配置文件中使用时可以配置以下参数:

  • mapperInterface:用于指定接口;
  • SqlSessionFactory:用于指定SqlSessionFactory;
  • SqlSessionTemplate:用于指定SqlSessionTemplate。如果与SqlSessionFactory同时设定,则只会启用SqlSessionTemplate。

在实际的项目中,DAO层会包含很多接口,如果每一个接口都在Spring配置文件中配置,不但会增加工作量,还会使得Spring配置文件非常臃肿。

③自动注入映射器(使用MapperScannerConfigurer方式)

Mybatis MapperScannerConfigurer 自动扫描 将Mapper接口生成代理注入到Spring

配置MapperScannerConfigurer

获得符合Mapper映射器要求的对象(相当于调用SqlSession的getMapper()方法)。

即在测试方法中的:UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

并且会将这些对象放到spring容器里面(默认的id是首字母小写之后的接口名比如Mapper映射器名为EmpDAO,则默认的id是empDAO,也可以使用@Repository来修改默认的id)

即功能为:MapperScannerConfigurer可以为我们自动生成各个Mapper的实例化Bean用来装入

  • basePackage:指定映射接口文件所在的包路径,当需要扫描多个包时可以使用分号或逗号作为分隔符。指定包路径后,会扫描该包及其子包中的所有文件。
  • annotationClass:指定了要扫描的注解名称,只有被注解标识的类才会被配置为映射器。
  • sqlSessionFactoryBeanName:指定在Spring中定义的SqlSessionFactory的Bean名称。
  • sqlSessionTemplateBeanName:指定在Spring中定义的SqlSessionTemplate的Bean名称。如果定义此属性,则sqlSessionFactoryBeanName将不起作用。
  • markerInterface:指定创建映射器的接口。

使用下面的 Spring 配置:

1
2
3
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="org.mybatis.spring.sample.mapper" />
</bean>

如果你需要指定 sqlSessionFactorysqlSessionTemplate,==那你应该要指定的是 bean 名而不是 bean 的引用,因此要使用 value 属性而不是通常的 ref 属性==:

1
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />

在mybatis-spring1.1.0以前,是通过<property name="sqlSessionFactory" ref="sqlSessionFactory"/>将SqlSessionFactory对象注入到sqlSessionFactory,这样做可能会有一个问题,就是在初始化MyBatis时,jdbc.properties文件还没被加载进来,dataSource的属性值没有被替换,就开始构造sqlSessionFactory类,属性值就会加载失败。在1.1.0以后,MapperScannerConfigure提供了String类型的sqlSessionFactoryBeanName,这样将bean name注入到sqlSessionFactoryBeanName,这样就会等到spring初始化完成后,再构建sqlSessionFactory。

关于SqlSessionFactoryBean、SqlSessionFactory、SqlSession:

SqlSessionFactoryBean—>SqlSessionFactory—>获取SqlSession对象—>获取Mapper对象—>执行SQL对话。

SqlSessionFactoryBean—>SqlSessionFactory—>获取SqlSession对象—>执行SQL对话。

因为:session.selectOne("cn.edu.ccc.ch9.dao.PersonMapper.selectByPrimaryKey", 1);

PersonMapper personMapper=session.getMapper(PersonMapper.class); personMapper.selectByPrimaryKey(1);是等效的

SqlSessionFactoryBean实现了SqlSessionFactory接口。

Spring和Mybatis配置文件整合后代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan
base-package="cn.edu.ccc.ch10.service" />
<!--读取db.properties -->
<context:property-placeholder
location="classpath:db.properties" />
<!-- 配置数据源 -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<!--数据库驱动 -->
<property name="driverClassName" value="${jdbc.driver}" />
<!--连接数据库的url -->
<property name="url" value="${jdbc.url}" />
<!--连接数据库的用户名 -->
<property name="username" value="${jdbc.username}" />
<!--连接数据库的密码 -->
<property name="password" value="${jdbc.password}" />
</bean>
<!-- 事务管理器,依赖于数据源 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!--开启事务注解 -->
<tx:annotation-driven
transaction-manager="transactionManager" />


<!--配置MyBatis工厂 -->
<bean id="sqlSessionFactory"
class="org.mybatis.spring.SqlSessionFactoryBean">
<!--注入数据源 -->
<property name="dataSource" ref="dataSource" />
<!-- 自动扫描dao目录, 省掉mapper-resource里的手工配置 -->
<property name="typeAliasesPackage"
value="cn.edu.ccc.ch10.dao" />
<!--指定核心配置文件位置 -->
<property name="mapperLocations"
value="classpath:cn/edu/ccc/ch10/dao/*.xml" />
</bean>

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="cn.edu.ccc.ch10.dao" />
<property name="sqlSessionFactoryBeanName"
value="sqlSessionFactory" />
</bean>

</beans>

dataSource等数据传给SqlSessionFactoryBean,Spring构建Bean得到SqlSessionFactory,MapperScannerConfigurer使用SqlSessionFactory获取session,再获取Mapper对象作为Bean,为Spring之后在Service层的注入使用。

注意:若配置了sqlSessionFactoryBeanName选项,则value需要和XML文件中的sqlSessionFactory的Id一致。否则找不到sqlSessionFactory报错。若不配置则会默认寻找

1
2
3
4
5
6
7
8
9
10
11
12
13
@Service
public class CustomerServiceImpl implements ICustomerService {

@Autowired
private CustomerMapper customerMapper;

@Override
public int insert(Customer customer) {
// TODO Auto-generated method stub
customerMapper.insert(customer);
return 0;
}
}

11、拓展:连接池

(1)Apache的dbcp2连接池

1
2
3
4
5
6
7
8
9
10
11
12
13
14
  <context:property-placeholder location="classpath:db.properties"/>
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
<property name="driverClassName" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="maxTotal" value="${jdbc.maxTotal}" />
<!--最大活动连接数量:连接池在同一时间能够分配的最大活动连接的数量, 如果设置为负数则表示不限制 默认为8 -->
<property name="maxIdle" value="${jdbc.maxIdle}" />
<!--最大空闲连接:连接池中容许保持空闲状态的最大连接数量,超过的空闲连接将被释放,如果设置为负数表示不限制
默认为8 -->
<property name="initialSize" value="${jdbc.initialSize}" />
<!--初始化连接数量:连接池启动时创建的初始化连接数量 默认为0 -->
</bean>
1
2
3
4
5
6
7
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis
jdbc.username=root
jdbc.password=root
jdbc.maxTotal=30
jdbc.maxIdle=10
jdbc.initialSize=5

(2)阿里巴巴Druid连接池

1
2
3
4
5
6
7
8
9
10
11
12
13
<bean name="dataSource“ class="com.alibaba.druid.pool.DruidDataSource"
init-method="init" destroy-method="close" >
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<!-- 初始化连接大小 -->
<property name="initialSize" value="0" />
<!-- 连接池最大使用连接数量 -->
<property name="maxActive" value="20" />
<!-- 连接池最小空闲 -->
<property name="minIdle" value="0" />
……
</bean>
1
2
3
4
5
<dependency>			
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.15</version>
</dependency>

12、其他

  • 1、关于Service层,本就是服务层,只是我们初学,才只有只调用Mapper即DAO层的方法

    1
    2
    3
    4
    5
    public Orders selectByPrimaryKey(Integer id) {
    // TODO Auto-generated method stub
    Orders selectByPrimaryKey = ordersMapper.selectByPrimaryKey(id);
    return selectByPrimaryKey;
    }

    实际上Service层,具有其他逻辑,例如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    public int insert(Orders record) {
    // TODO Auto-generated method stub
    int insert = ordersMapper.insert(record);
    if (insert > 0) {
    List<Product> productList = record.getProductList();
    for (Product p : productList) {
    Map orderItem = new HashMap();
    orderItem.put("orders_id", record.getId());
    orderItem.put("product_id", p.getId());
    int addOrdersItem = ordersMapper.addOrdersItem(orderItem);
    System.out.println("插入成功(orderItem):" + orderItem);
    }
    }
    return insert;
    }

    这样应用层只需要调用即可。

-----------------------本文结束 感谢阅读-----------------------
坚持原创技术分享,您的支持将鼓励我继续创作!恰饭^.^~