Mybatis学习总结

Mybatis学习总结().初探Mybatis

回顾JDBC编程

1.创建Maven工程,导入mysql依赖

<!-- MySql -->

<dependency>

    <groupId>mysql</groupId>

    <artifactId>mysql-connector-java</artifactId>

    <version>5.1.32</version>

</dependency>

2.需求:根据用户id查询用户信息

用户表:

DROP TABLE IF EXISTS `tb_user`;

CREATE TABLE `tb_user` (

`id` bigint(20) NOT NULL AUTO_INCREMENT,

`user_name` varchar(100) DEFAULT NULL COMMENT '用户名',

`password` varchar(100) DEFAULT NULL COMMENT '密码',

`name` varchar(100) DEFAULT NULL COMMENT '姓名',

`age` int(10) DEFAULT NULL COMMENT '年龄',

`sex` tinyint(1) DEFAULT NULL COMMENT '性别,1男性,2女性',

`birthday` date DEFAULT NULL COMMENT '出生日期',

`created` datetime DEFAULT NULL COMMENT '创建时间',

`updated` datetime DEFAULT NULL COMMENT '更新时间',

PRIMARY KEY (`id`),

UNIQUE KEY `username` (`user_name`)

) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;

-- ----------------------------

-- Records of tb_user

-- ----------------------------

INSERT INTO `tb_user` VALUES ('1', 'zhangsan', '123456', '张三', '30', '1', '1984-08-08', '2014-09-19 16:56:04', '2014-09-21 11:24:59');

INSERT INTO `tb_user` VALUES ('2', 'lisi', '123456', '李四', '21', '2', '1991-01-01', '2014-09-19 16:56:04', '2014-09-19 16:56:04');

INSERT INTO `tb_user` VALUES ('3', 'wangwu', '123456', '王五', '22', '2', '1989-01-01', '2014-09-19 16:56:04', '2014-09-19 16:56:04');

INSERT INTO `tb_user` VALUES ('4', 'zhangwei', '123456', '张伟', '20', '1', '1988-09-01', '2014-09-19 16:56:04', '2014-09-19 16:56:04');

INSERT INTO `tb_user` VALUES ('5', 'lina', '123456', '李娜', '28', '1', '1985-01-01', '2014-09-19 16:56:04', '2014-09-19 16:56:04');

INSERT INTO `tb_user` VALUES ('6', 'lilei', '123456', '李磊', '23', '1', '1988-08-08', '2014-09-20 11:41:15', '2014-09-20 11:41:15');

SQL:

SELECT * FROM tb_user WHERE id = ?

3.编写JDBC程序

/**

* @Description:Jdbc连接数据库

* @author xingyuchao

* @date 2016年8月2日 下午2:42:17

* @version V1.0

*/

public class JDBCTest {

public static void main(String[] args) {

ResultSet resultSet = null;

PreparedStatement preparedStatement = null;

Connection connection = null;

try {

// 加载驱动

Class.forName("com.mysql.jdbc.Driver");

// 创建数据库连接

String url = "jdbc:mysql://127.0.0.1:3306/mybatis";

String user = "root";

String password = "123456";

connection = DriverManager.getConnection(url, user, password);

// 创建statmenet

String sql = "SELECT * FROM tb_user WHERE id = ?";

preparedStatement = connection.prepareStatement(sql);

// 设置参数、执行sql,2个参数,第一个是参数的下标,从1开始,第二个参数数据查询条件数据

preparedStatement.setLong(1, 1L);

resultSet = preparedStatement.executeQuery();

// 遍历结果集

while (resultSet.next()) {

System.out.println("ID: " + resultSet.getLong("id"));

System.out.println("userName: " + resultSet.getString("user_name"));

System.out.println("password: " + resultSet.getString("password"));

System.out.println("name: " + resultSet.getString("name"));

}

} catch (Exception e) {

e.printStackTrace();

} finally {

// 释放连接(资源)

if (null != resultSet) {

try {

resultSet.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

if(null != preparedStatement){

try {

preparedStatement.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

if(null != connection){

try {

connection.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

}

}

}

存在的问题:

1、 加载驱动的问题

每次执行都要加载驱动

驱动名称硬编码java代码中,如需修改驱动名称时,需要修改java文件再编译

解决方案:将驱动名称放置到外部的配置文件中解决。

2、 数据库连接信息硬编码到java代码中,解决:外部配置文件解决。

3、 设置参数问题

参数下标硬编码到java代码中,需要人工判断参数位置,使用不便

参数值硬编码到代码中,如果要修改参数或者是根据不同的参数值查询,无法实现,解决:通过参数传入解决。

希望:能否自动判断参数下标和类型。

4、 遍历结果集存在的问题,需要人工判断字段名以及位置或者参数的类型,导致使用不方便

希望:如果,能将结果集直接映射为一个pojo对象,那么使用就方便多了

5、 频繁的创建连接、关闭连接,导致资源浪费,影响应用的性能,解决:使用连接池解决。

解决:使用Mybatis解决。

Mybatis简介

Mybatis的前身是iBatis,Apache的一个开源项目,2010年这个项目从Apache迁移到Google Code改名为Mybatis 之后将版本升级到3.X,其官网:http://blog.mybatis.org/,从3.2版本之后迁移到github,目前最新稳定版本为:3.2.8。

Mybatis是一个类似于Hibernate的ORM持久化框架,支持普通SQL查询,存储过程以及高级映射。Mybatis通过使用简单的XML或注解用于配置和原始映射,将接口和POJO对象映射成数据库中的记录。

由于Mybatis是直接基于JDBC做了简单的映射包装,所有从性能角度来看:JDBC > Mybatis > Hibernate

Mybatis的官网:http://blog.mybatis.org/

下载地址(3.2.8):https://github.com/mybatis/mybatis-3/releases

官方文档:http://www.mybatis.org/mybatis-3/

官方文档(中文版):http://www.mybatis.org/mybatis-3/zh/index.html

mybatis-spring文档:http://www.mybatis.org/spring/zh/index.html

mybatis手动控制事务:http://toknowme.iteye.com/blog/2226645

Mybatis的整体架构

1、 mybatis配置文件,有2类配置文件

全局配置文件,只能有一个,文件名不是固定的,约定文件名:mybatis-config.xml,配置了运行参数、插件、连接池等信息。

Mapper.xml,映射文件,在整个mybatis中可以有多个配置文件,配置多个Statement(SQL)

2、 通过配置文件构造出SqlSessionFactory

3、 通过SqlSessionFactory获取到Sqlsession,通过SqlSession就可以操作数据库。

4、 SqlSession同底层的执行器来执行Statement(SQL),mybatis提供了2种执行器的实现

基本实现

带有缓存功能的实现

5、 执行器通过定义的Mapped Statement对象来执行SQL

6、 参数传入:参数类型有三种,HashMap、基本数据类型、POJO对象

7、 结果输出:输出结果集类型有三种,HashMap、基本数据类型、POJO对象

Mybatis使用步骤

1.导入依赖:

<dependency>

    <groupId>org.mybatis</groupId>

    <artifactId>mybatis</artifactId>

    <version>3.2.8</version>

</dependency>

2.编写全局配置文件 mybatis-config.xml

jdbc.properties

jdbc.driver=com.mysql.jdbc.Driver

jdbc.url=jdbc:mysql://127.0.0.1:3306/mybatis?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true

jdbc.username=root

jdbc.password=123456

mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE configuration

PUBLIC "-//mybatis.org//DTD Config 3.0//EN"

"http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>

    <!-- 加载配置文件 -->

    <properties resource="jdbc.properties"/>

    <!--

        配置环境,数据库连接

     -->

    <environments default="development">

        <environment id="development">

            <transactionManager type="JDBC" />

            <dataSource type="POOLED">

                <property name="driver" value="${jdbc.driver}" />

                <property name="url" value="${jdbc.url}" />

                <property name="username" value="${jdbc.username}" />

                <property name="password" value="${jdbc.password}" />

            </dataSource>

        </environment>

    </environments>

    <!-- <mappers>

        <mapper resource="UserMapper.xml" />

    </mappers> -->

</configuration>

3.构建SqlSessionFactory

public class Mybatis {

public static void main(String[] args) throws Exception {

//定义配置文件名称

String resource = "mybatis-config.xml";

//通过Resources工具类读取配置文件

InputStream inputStream = Resources.getResourceAsStream(resource);

//通过SqlSessionFactoryBuilder构造SqlSessionFactory

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

//或得到SqlSession

SqlSession session = sqlSessionFactory.openSession();

System.out.println(sqlSessionFactory);

System.out.println(session);

}

}

4.配置statement UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE mapper

PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"

"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="abc">

    <select id="queryUserById" resultType="cn.zto.mybatis.pojo.User">

        SELECT * FROM tb_user WHERE id = #{id}

    </select>

</mapper>

User.java

public class User {

private Long id;

// 用户名

private String userName;

// 密码

private String password;

// 姓名

private String name;

// 年龄

private Integer age;

// 性别,1男性,2女性

private Integer sex;

// 出生日期

private Date birthday;

// 创建时间

private Date created;

// 更新时间

private Date updated;

//getter and setter

}

5.将UserMapper.xml加入到Mybatis全局配置文件中:

<mappers>

    <mapper resource="UserMapper.xml" />

</mappers>

6.根据Id查询用户信息

//名称空间.statemement

User user = session.selectOne("abc.queryUserById", 1);

System.out.println(user);

session.close();

测试结果:

如上无法获取到userName属性的值,是因为数据库中的字段为user_name,而对应到java对象的属性中为userName。因为需要在全局配置文件中加入驼峰标示配置(或者通过 sql语句字段起别名方式解决)

<settings>

    <!-- 开启驼峰映射 -->

    <setting name="mapUnderscoreToCamelCase" value="true"/>

</settings>

添加日志支持

1.引入slf依赖

<dependency>

    <groupId>org.slf4j</groupId>

    <artifactId>slf4j-log4j12</artifactId>

    <version>1.6.4</version>

</dependency>

Mybatis学习总结().Mybatis普通方式实现CRUD及动态代理方式实现CRUD

普通方式实现CRUD

user.java

public class User {

private Long id;

// 用户名

private String userName;

// 密码

private String password;

// 姓名

private String name;

// 年龄

private Integer age;

// 性别,1男性,2女性

private Integer sex;

// 出生日期

private Date birthday;

// 创建时间

private Date created;

// 更新时间

private Date updated;

//getter and setter

}

定义接口UserDAO.java

public interface UserDAO {

/**

* 根据id查询用户数据

*

* @param id

* @return

*/

public User queryUserById(Long id);

/**

* 新增user数据

*

* @param user

*/

public void saveUser(User user);

/**

* 更新user数据

*

* @param user

*/

public void updateUser(User user);

/**

* 根据id删除用户数据

*

* @param id

*/

public void deleteUserById(Long id);

}

定义实现类UserDAOImpl.java

public class UserDAOImpl implements UserDAO{

private SqlSessionFactory sqlSessionFactory;

public UserDAOImpl(SqlSessionFactory sqlSessionFactory){

this.sqlSessionFactory = sqlSessionFactory;

}

@Override

public User queryUserById(Long id) {

SqlSession session = this.sqlSessionFactory.openSession();

User user = session.selectOne("userDAO.queryUserById", id);

session.close();

return user;

}

@Override

public void saveUser(User user) {

SqlSession session = this.sqlSessionFactory.openSession();

session.insert("userDAO.saveUser", user);

//提交事物

session.commit();

session.close();

}

@Override

public void updateUser(User user) {

SqlSession session = this.sqlSessionFactory.openSession();

session.update("userDAO.updateUser", user);

//提交事物

session.commit();

session.close();

}

@Override

public void deleteUserById(Long id) {

SqlSession session = this.sqlSessionFactory.openSession();

session.delete("userDAO.deleteUserById", id);

//提交事物

session.commit();

session.close();

}

}

编写UserDAOMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE mapper

PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"

"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="userDAO">

    <select id="queryUserById" resultType="cn.zto.mybatis.pojo.User">

        SELECT *,user_name userName FROM tb_user WHERE id = #{id}

    </select>

    <insert id="saveUser" parameterType="cn.zto.mybatis.pojo.User">

        INSERT INTO tb_user (

            id,

            user_name,

            password,

            name,

            age,

            sex,

            birthday,

            created,

            updated

        )

        VALUES

            (

                NULL,

                #{userName},

                #{password},

                #{name},

                #{age},

                #{sex},

                #{birthday},

                NOW(),

                NOW()

            );

    </insert>

    <update id="updateUser" parameterType="cn.zto.mybatis.pojo.User">

        UPDATE tb_user

        SET

         user_name = #{userName},

         password = #{password},

         name = #{name},

         age = #{age},

         sex = #{sex},

         birthday = #{birthday},

         updated = NOW()

        WHERE

            id = #{id}

    </update>

    <delete id="deleteUserById">

        DELETE FROM tb_user WHERE id = #{id}

    </delete>

</mapper>

定义全局配置文件mybaits-config.xml

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE configuration

PUBLIC "-//mybatis.org//DTD Config 3.0//EN"

"http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>

    <!-- 加载配置文件 -->

    <properties resource="jdbc.properties"/>

    <settings>

        <!-- 开启驼峰映射 -->

        <setting name="mapUnderscoreToCamelCase" value="true"/>

    </settings>

    <!--

        配置环境,数据库连接

     -->

    <environments default="development">

        <environment id="development">

            <transactionManager type="JDBC" />

            <dataSource type="POOLED">

                <property name="driver" value="${jdbc.driver}" />

                <property name="url" value="${jdbc.url}" />

                <property name="username" value="${jdbc.username}" />

                <property name="password" value="${jdbc.password}" />

            </dataSource>

        </environment>

    </environments>

    <mappers>

        <mapper resource="UserDAOMapper.xml" />

    </mappers>

</configuration>

添加Junit依赖,并编写测试代码

package cn.zto.mybatis.dao.impl;

import java.io.InputStream;

import java.util.Date;

import org.apache.ibatis.io.Resources;

import org.apache.ibatis.session.SqlSessionFactory;

import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import org.junit.Before;

import org.junit.Test;

import cn.zto.mybatis.dao.UserDAO;

import cn.zto.mybatis.dao.impl.UserDAOImpl;

import cn.zto.mybatis.pojo.User;

/**

* @Description: 普通方式实现crud

* @author xingyuchao

* @date 2016年8月2日 下午3:13:00

* @version V1.0

*/

public class UserDAOImplTest {

private UserDAO userDAO;

@Before

public void setUp() throws Exception {

String resource = "mybatis-config.xml";

InputStream inputStream = Resources.getResourceAsStream(resource);

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

this.userDAO = new UserDAOImpl(sqlSessionFactory);

}

@Test

public void testQueryUserById() {

User user = this.userDAO.queryUserById(2L);

System.out.println(user);

}

@Test

public void testSaveUser() {

User user = new User();

user.setAge(20);

user.setBirthday(new Date());

user.setName("test_1");

user.setPassword("123456");

user.setSex(1);

user.setUserName("test_username_1");

this.userDAO.saveUser(user);

}

@Test

public void testUpdateUser() {

User user = this.userDAO.queryUserById(2L);

user.setAge(40);

this.userDAO.updateUser(user);

}

@Test

public void testDeleteUserById() {

this.userDAO.deleteUserById(5L);

}

}

实现DAO接口中的问题

1、 实现比较繁琐,接口-->实现类 --> Mapper.xml

2、 实现类中使用Mybatis的方法非常的类似

3、 sql statement 硬编码到java代码中。

思考:能否只编写接口,不写实现类,编写Mapper.xml即可?

动态代理方式实现CRUD

流程:

1.mybatis首先读取全局配置文件mybatis-config.xml

2.加载UserDAO2Mapper.xml,读到命名空间找到相应的接口,找到接口中的方法名和statement中的id相互对应起来之后,帮我们生成一个动态代理的实现类,因此我们就不需要自己手动写实现类了.

UserDAOImplTest2.java

package cn.zto.mybatis.dao.impl;

import java.io.InputStream;

import java.util.Date;

import org.apache.ibatis.io.Resources;

import org.apache.ibatis.session.SqlSession;

import org.apache.ibatis.session.SqlSessionFactory;

import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import org.junit.Before;

import org.junit.Test;

import cn.zto.mybatis.dao.UserDAO;

import cn.zto.mybatis.pojo.User;

/**

*

* @Description: 动态代理实现类测试用例

* @author xingyuchao

* @date 2016年8月2日 下午3:13:38

* @version V1.0

*/

public class UserDAOImplTest2 {

private UserDAO userDAO;

@Before

public void setUp() throws Exception {

String resource = "mybatis-config.xml";

InputStream inputStream = Resources.getResourceAsStream(resource);

//build方法也可以配置数据库连接使用哪一个

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream,"test");

//注意:这里没有了实现类,需要将事务设置为自动

SqlSession sqlSession = sqlSessionFactory.openSession(true);

//通过sqlSession获取到动态代理的实现类

this.userDAO = sqlSession.getMapper(UserDAO.class);

}

@Test

public void testQueryUserById() {

User user = this.userDAO.queryUserById(1L);

System.out.println(user);

}

@Test

public void testSaveUser() {

User user = new User();

user.setAge(20);

user.setBirthday(new Date());

user.setName("test_3");

user.setPassword("123456");

user.setSex(1);

user.setUserName("test_username_3");

this.userDAO.saveUser(user);

}

@Test

public void testUpdateUser() {

User user = this.userDAO.queryUserById(2L);

user.setAge(35);

this.userDAO.updateUser(user);

}

@Test

public void testDeleteUserById() {

this.userDAO.deleteUserById(7L);

}

}

UserDAO2Mapper.xml

Mapper中Namespace的定义本身是没有限制的,只要不重复即可,但是如果要想使用Mybatis提供的DAO的动态代理,namespace必须为mapper接口的全路径

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE mapper

PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"

"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="cn.zto.mybatis.dao.UserDAO">

    <select id="queryUserById" resultType="User" parameterType="Long">

        SELECT * FROM tb_user WHERE id = #{id}

    </select>

    <insert id="saveUser" parameterType="cn.zto.mybatis.pojo.User">

        INSERT INTO tb_user (

            id,

            user_name,

            password,

            name,

            age,

            sex,

            birthday,

            created,

            updated

        )

        VALUES

            (

                NULL,

                #{userName},

                #{password},

                #{name},

                #{age},

                #{sex},

                #{birthday},

                NOW(),

                NOW()

            );

    </insert>

    <update id="updateUser" parameterType="cn.zto.mybatis.pojo.User">

        UPDATE tb_user

        SET

         user_name = #{userName},

         password = #{password},

         name = #{name},

         age = #{age},

         sex = #{sex},

         birthday = #{birthday},

         updated = NOW()

        WHERE

            id = #{id}

    </update>

    <delete id="deleteUserById">

        DELETE FROM tb_user WHERE id = #{id}

    </delete>

</mapper>

mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE configuration

PUBLIC "-//mybatis.org//DTD Config 3.0//EN"

"http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>

    <!-- 加载配置文件 -->

    <properties resource="jdbc.properties"/>

    <settings>

        <!-- 开启驼峰映射 -->

        <setting name="mapUnderscoreToCamelCase" value="true"/>

    </settings>

    <typeAliases>

        <!-- <typeAlias type="cn.zto.mybatis.pojo.User" alias="User"/> -->

        <!--

            配置扫描包,更适合企业开发

         -->

        <package name="cn.zto.mybatis.pojo" />

    </typeAliases>

    <!--

        配置环境,数据库连接

     -->

    <environments default="development">

        <environment id="development">

            <transactionManager type="JDBC" />

            <dataSource type="POOLED">

                <property name="driver" value="${jdbc.driver}" />

                <property name="url" value="${jdbc.url}" />

                <property name="username" value="${jdbc.username}" />

                <property name="password" value="${jdbc.password}" />

            </dataSource>

        </environment>

        <environment id="test">

            <transactionManager type="JDBC" />

            <dataSource type="POOLED">

                <property name="driver" value="${jdbc.driver}" />

                <property name="url" value="${jdbc.url}" />

                <property name="username" value="${jdbc.username}" />

                <property name="password" value="${jdbc.password}" />

            </dataSource>

        </environment>

    </environments>

    <mappers>

        <mapper resource="UserDAO2Mapper.xml" />

    </mappers>

</configuration>

其他的实体等一样

使用动态代理总结:

使用mapper接口不用写接口实现类即可完成数据库操作,使用非常简单,也是官方所推荐的使用方法。

使用mapper接口的必须具备以几个条件:

Mapper的namespace必须和mapper接口的全路径一致。

Mapper接口的方法名必须和sql定义的id一致。

Mapper接口中方法的输入参数类型必须和sql定义的parameterType一致(parameterType可以省略)。

Mapper接口中方法的输出参数类型必须和sql定义的resultType一致。

Mybatis学习总结().Mybatis全局配置文件

Mybatis-Config配置

在config.xml配置文件中的内容和顺序如下:

properties 属性

settings 设置

typeAliases 类型别名

typeHandlers 类型处理器

objectFactory 对象工厂

plugins 插件

environments 环境

environment 环境变量

transactionManager 事务管理器

dataSource 数据源

mappers 映射器

properties属性

<!-- 加载配置文件 -->

<properties resource="jdbc.properties"/>

这样引用:

<property name="driver" value="${jdbc.driver}" />

setting设置

设置参数

描述

有效值

默认值

cacheEnabled

该配置影响的所有映射器中配置的缓存的全局开关。

true | false

true

lazyLoadingEnabled

延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。特定关联关系中可通过设置fetchType属性来覆盖该项的开关状态。

true | false

false

aggressiveLazyLoading

当启用时,带有延迟加载属性的对象的加载与否完全取决于对任意延迟属性的调用;反之,每种属性将会按需加载。

true | false

true

multipleResultSetsEnabled

是否允许单一语句返回多结果集(需要兼容驱动)。

true | false

true

useColumnLabel

使用列标签代替列名。不同的驱动在这方面会有不同的表现,具体可参考相关驱动文档或通过测试这两种不同的模式来观察所用驱动的结果。

true | false

true

useGeneratedKeys

允许 JDBC 支持自动生成主键,需要驱动兼容。如果设置为 true 则这个设置强制使用自动生成主键,尽管一些驱动不能兼容但仍可正常工作(比如 Derby)。

true | false

False

autoMappingBehavior

指定 MyBatis 是否以及如何自动映射指定的列到字段或属性。NONE 表示取消自动映射;PARTIAL 只会自动映射没有定义嵌套结果集映射的结果集。FULL 会自动映射任意复杂的结果集(包括嵌套和其他情况)。

NONE, PARTIAL, FULL

PARTIAL

defaultExecutorType

配置默认的执行器。SIMPLE 就是普通的执行器;REUSE 执行器会重用预处理语句(prepared statements);BATCH 执行器将重用语句并执行批量更新。

SIMPLE REUSE BATCH

SIMPLE

defaultStatementTimeout

设置超时时间,它决定驱动等待数据库响应的秒数。

Any positive integer

Not Set (null)

safeRowBoundsEnabled

允许在嵌套语句中使用行分界(RowBounds)。

true | false

False

mapUnderscoreToCamelCase

是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的类似映射。

true | false

False

localCacheScope

MyBatis 利用本地缓存机制(Local Cache)防止循环引用(circular references)和加速重复嵌套查询。默认值为 SESSION,这种情况下会缓存一个会话中执行的所有查询。若设置值为 STATEMENT,本地会话仅用在语句执行上,对相同 SqlSession 的不同调用将不会共享数据。

SESSION | STATEMENT

SESSION

jdbcTypeForNull

当没有为参数提供特定的 JDBC 类型时,为空值指定 JDBC 类型。某些驱动需要指定列的 JDBC 类型,多数情况直接用一般类型即可,比如 NULLVARCHAR 或 OTHER

JdbcType enumeration. Most common are: NULL, VARCHAR and OTHER

OTHER

lazyLoadTriggerMethods

指定哪个对象的方法触发一次延迟加载。

A method name list separated by commas

equals,clone,hashCode,toString

defaultScriptingLanguage

指定动态 SQL 生成的默认语言。

A type alias or fully qualified class name.

org.apache.ibatis.scripting.xmltags.XMLDynamicLanguageDriver

callSettersOnNulls

指定当结果集中值为 null 的时候是否调用映射对象的 settermap 对象时为 put)方法,这对于有 Map.keySet() 依赖或 null 值初始化的时候是有用的。注意原始类型(intboolean等)是不能设置成 null 的。

true | false

false

logPrefix

指定 MyBatis 增加到日志名称的前缀。

Any String

Not set

logImpl

指定 MyBatis 所用日志的具体实现,未指定时将自动查找。

SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING

Not set

proxyFactory

 Mybatis 用来创建具有延迟加载能力的对象设置代理工具。

CGLIB | JAVASSIST

CGLIB

mapUnderscoreToCamelCase用法:

<settings>

    <!-- 开启驼峰映射 -->

    <setting name="mapUnderscoreToCamelCase" value="true"/>

</settings>

typeAliases 类型别名

类型别名视为java类型命名一个短的名字,它只和xml配置有关.

<typeAliases>

     <!-- 别名:

     type: 指定java对象类型

     alias: 别名名称 -->

     <typeAlias type="cn.zto.mybatis.pojo.User" alias="User"/>

</typeAliases>

引用:

<select id="queryUserById" resultType="User" parameterType="Long">

    SELECT * FROM tb_user WHERE id = #{id}

</select>

<typeAliases>

     <!-- 别名:

     type: 指定java对象类型

     alias: 别名名称 -->

     <!-- <typeAlias type="cn.zto.mybatis.pojo.User" alias="User"/>

     <!--

        配置扫描包,更适合企业开发

        指定扫描包,mybatis会将该包下所有的类生成一个别名

        别名的首字母不区分大小写,但是,推荐使用大写.

     -->

     <package name="cn.zto.mybatis.pojo" />

</typeAliases>

引用:

<select id="queryUserById" resultType="User" parameterType="Long">

    SELECT * FROM tb_user WHERE id = #{id}

</select>

Mybatis提供的默认别名:

已经为普通的 Java 类型内建了许多相应的类型别名。它们都是大小写不敏感的,需要注意的是由于重载原始类型的名称所做的特殊处理。

别名

映射的类型

_byte

byte

_long

long

_short

short

_int

int

_integer

int

_double

double

_float

float

_boolean

boolean

string

String

byte

Byte

long

Long

short

Short

int

Integer

integer

Integer

double

Double

float

Float

boolean

Boolean

date

Date

decimal

BigDecimal

bigdecimal

BigDecimal

object

Object

map

Map

hashmap

HashMap

list

List

arraylist

ArrayList

collection

Collection

iterator

Iterator

typeHandlers 类型处理器

类型处理器是在设置参数,以及从Restult中检索值来匹配java数据类型,Mybatis提供非常多的默认类型处理器,一般情况下都可以满足日常的使用,不需要自定义处理器。

不常用 可以参考文档

plugins 插件(拦截器)

MyBatis 允许你在已映射语句执行过程中的某一点进行拦截调用。默认情况下,MyBatis 允许使用插件来拦截的方法调用包括:

可以在一下的几个点来做拦截。

Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed) 做执行的时候

ParameterHandler (getParameterObject, setParameters) 设置参数的时候

ResultSetHandler (handleResultSets, handleOutputParameters) 结果集的时候

StatementHandler (prepare, parameterize, batch, update, query) 将sql映射成statement对象的时候

自定义拦截器:

environments 环境

MyBatis 可以配置成适应多种环境,这种机制有助于将 SQL 映射应用于多种数据库之中,现实情况下有多种理由需要这么做。例如,开发、测试和生产环境需要有不同的配置;或者共享相同 Schema 的多个生产数据库,想使用相同的 SQL 映射。

不过要记住:尽管可以配置多个环境,每个 SqlSessionFactory 实例只能选择其一。

所以,如果你想连接两个数据库,就需要创建两个 SqlSessionFactory 实例,每个数据库对应一个。而如果是三个数据库,就需要三个实例,依此类推,记起来很简单:

每个数据库对应一个 SqlSessionFactory 实例

<!--

    配置环境,数据库连接

-->

<environments default="development">

    <environment id="development">

        <transactionManager type="JDBC" />

        <dataSource type="POOLED">

            <property name="driver" value="${jdbc.driver}" />

            <property name="url" value="${jdbc.url}" />

            <property name="username" value="${jdbc.username}" />

            <property name="password" value="${jdbc.password}" />

        </dataSource>

    </environment>

    <environment id="test">

        <transactionManager type="JDBC" />

        <dataSource type="POOLED">

            <property name="driver" value="${jdbc.driver}" />

            <property name="url" value="${jdbc.url}" />

            <property name="username" value="${jdbc.username}" />

            <property name="password" value="${jdbc.password}" />

        </dataSource>

    </environment>

</environments>

为了指定创建哪种环境,只要将它作为可选的参数传递给 SqlSessionFactoryBuilder 即可。可以接受环境配置的两个方法签名是:

然这种方式也可以做到很方便的分离多个环境,但是在实际使用场景下我们都是更多的使用Spring来管理数据源,做环境的分离。

映射器(mappers)

既然 MyBatis 的行为已经由上述元素配置完了,我们现在就要定义 SQL 映射语句了。但是首先我们需要告诉 MyBatis 到哪里去找到这些语句。Java 在自动查找这方面没有提供一个很好的方法,所以最佳的方式是告诉 MyBatis 到哪里去找映射文件。你可以使用相对于类路径的资源引用,或完全限定资源定位符(包括 file:/// 的 URL),或类名和包名等。例如:

<!-- Using classpath relative resources 路径相对于资源目录跟路径:-->

<mappers>

<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>

<mapper resource="org/mybatis/builder/BlogMapper.xml"/>

<mapper resource="org/mybatis/builder/PostMapper.xml"/>

</mappers>

<!-- Using url fully qualified paths 使用完整的文件路径:-->

<mappers>

<mapper url="file:///var/mappers/AuthorMapper.xml"/>

<mapper url="file:///var/mappers/BlogMapper.xml"/>

<mapper url="file:///var/mappers/PostMapper.xml"/>

</mappers>

<!-- Using mapper interface classes使用mapper接口类路径,注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。-->

<mappers>

<mapper class="org.mybatis.builder.AuthorMapper"/>

<mapper class="org.mybatis.builder.BlogMapper"/>

<mapper class="org.mybatis.builder.PostMapper"/>

</mappers>

<!-- Register all interfaces in a package as mappers 使用Mapper接口扫描包 -->

<mappers>

<package name="org.mybatis.builder"/>

</mappers>

Mybatis学习总结().Mapper映射文件

Mapper映射文件是在实际开发过程中使用最多的。Mapper文件中包含的元素有:

cache – 配置给定命名空间的缓存。

cache-ref – 从其他命名空间引用缓存配置。

resultMap – 映射复杂的结果对象。

sql – 可以重用的 SQL 块,也可以被其他语句引用。

insert – 映射插入语句

update – 映射更新语句

delete – 映射删除语句

select – 映射查询语句

select – 映射查询语句

<select id="queryUserById" resultType="User" parameterType="Long">

    SELECT * FROM tb_user WHERE id = #{id}

</select>

id:是当前命名空间下的Statement的唯一标识(必须属性);

parameterType:输入的参数类型(可以省略);

resultType:将结果集映射为的java对象类型(必须属性);

标签内部:编写SQL语句

insert – 映射插入语句

<insert id="saveUser" parameterType="cn.zto.mybatis.pojo.User">

    INSERT INTO tb_user (

        id,

        user_name,

        password,

        name,

        age,

        sex,

        birthday,

        created,

        updated

    )

    VALUES

        (

            NULL,

            #{userName},

            #{password},

            #{name},

            #{age},

            #{sex},

            #{birthday},

            NOW(),

            NOW()

        );

</insert>

id:是当前命名空间下的Statement的唯一标识(必须属性);

parameterType:输入的参数类型(可以省略);

标签内部:编写SQL语句

获取自增Id

<!-- useGeneratedKeys: 开启自增id回填

keyColumn: 指定数据库表中列名

keyProperty: 指定对象的属性名

如果keyColumn 和 keyProperty 相同,则keyColumn可以省略不写 -->

<insert id="saveUser" parameterType="cn.zto.mybatis.pojo.User" useGeneratedKeys="true" keyColumn="id" keyProperty="id">

    INSERT INTO tb_user (

        id,

        user_name,

        password,

        name,

        age,

        sex,

        birthday,

        created,

        updated

    )

    VALUES

        (

            NULL,

            #{userName},

            #{password},

            #{name},

            #{age},

            #{sex},

            #{birthday},

            NOW(),

            NOW()

        );

</insert>

@Test

public void testSaveUser() {

User user = new User();

user.setAge(20);

user.setBirthday(new Date());

user.setName("test_3");

user.setPassword("123456");

user.setSex(1);

user.setUserName("test_username_3");

this.userMapper.saveUser(user);

//获取自增id

System.out.println("id:"+user.getId());

}

update – 映射更新语句

<update id="updateUser" parameterType="cn.zto.mybatis.pojo.User">

    UPDATE tb_user

    SET

     user_name = #{userName},

     password = #{password},

     name = #{name},

     age = #{age},

     sex = #{sex},

     birthday = #{birthday},

     updated = NOW()

    WHERE

        id = #{id}

</update>

id:是当前命名空间下的Statement的唯一标识(必须属性);

parameterType:输入的参数类型(可以省略);

标签内部:编写SQL语句

delete – 映射删除语句

<delete id="deleteUserById">

    DELETE FROM tb_user WHERE id = #{id}

</delete>

id:是当前命名空间下的Statement的唯一标识(必须属性);

parameterType:输入的参数类型(可以省略);

标签内部:编写SQL语句

parameterType的传入参数

传入类型有三种:

1、简单类型,string、long、integer等

2、Pojo类型,User等

3、HashMap类型。

在使用#{}传参时,#{}只是做占位符,与参数名无关。

在使用${}传参时,是通过参数名获取参数的,如果没有指定参数名则可以通过value获取,如果指定则需要按照名称获取。

parameterType的传入多个参数

当Mapper接口中需要传递多个参数时有两种方法传递:

使用默认规则获取参数;

使用@Param注解表明参数传递;

其实parameterType参数是可以省略的

UserMapper.java

package cn.zto.mybatis.mapper;

import cn.zto.mybatis.pojo.User;

public interface UserMapper {

/**

* 模拟登陆

* @Title: login

* @Description: TODO(这里用一句话描述这个方法的作用)

* @param: @param userName

* @param: @param passwd

* @param: @return

* @return: User

* @throws

*/

public User login(String userName,String passwd);

}

UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE mapper

PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"

"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="cn.zto.mybatis.mapper.UserMapper">

    <select id="login" resultType="User" >

        SELECT * FROM tb_user WHERE user_name = #{userName} and password = #{passwd}

    </select>

</mapper>

测试

package cn.zto.mybatis.mapper;

import java.io.InputStream;

import org.apache.ibatis.io.Resources;

import org.apache.ibatis.session.SqlSession;

import org.apache.ibatis.session.SqlSessionFactory;

import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import org.junit.Before;

import org.junit.Test;

import cn.zto.mybatis.pojo.User;

/**

* 动态代理实现类测试用例

*

*/

public class UserMapperTest {

private UserMapper userMapper;

@Before

public void setUp() throws Exception {

String resource = "mybatis-config.xml";

InputStream inputStream = Resources.getResourceAsStream(resource);

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream, "test");

SqlSession sqlSession = sqlSessionFactory.openSession(true);

// 通过sqlSession获取到动态代理的实现类

this.userMapper = sqlSession.getMapper(UserMapper.class);

}

@Test

public void testLogin() {

User user = this.userMapper.login("zhangsan","123");

System.out.println(user);

}

}

结果出错,错误信息参数userName找不到,可用参数为0,1,param1,param2

修改参数:

<select id="login" resultType="User" >

    <!-- SELECT * FROM tb_user WHERE user_name = #{userName} and password = #{passwd} -->

    SELECT * FROM tb_user WHERE user_name = #{0} and password = #{1}

</select>

或者:

<select id="login" resultType="User" >

    <!-- SELECT * FROM tb_user WHERE user_name = #{userName} and password = #{passwd} -->

    SELECT * FROM tb_user WHERE user_name = #{param1} and password = #{param2}

</select>

测试通过。这种方式为使用默认规则参数,还有一种是通过@param注解获取参数

/**

* 模拟登陆

* @Title: login

* @Description: TODO(这里用一句话描述这个方法的作用)

* @param: @param userName

* @param: @param passwd

* @param: @return

* @return: User

* @throws

*/

public User login(@Param("userName")String userName,@Param("passwd")String passwd);

<select id="login" resultType="User" >

    SELECT * FROM tb_user WHERE user_name = #{userName} and password = #{passwd}

    <!-- SELECT * FROM tb_user WHERE user_name = #{param1} and password = #{param2} -->

</select>

ResultType结果输出

输出类型有三种:

简单类型,string、long、integer等

Pojo类型,User等

HashMap类型。

'#{}'与'${}'的区别

在Mybatis的mapper中,参数传递有2种方式,一种是#{}另一种是${},两者有着很大的区别:

#{} 实现的是sql语句的预处理参数,之后执行sql中用?号代替,使用时不需要关注数据类型,Mybatis自动实现数据类型的转换。并且可以防止SQL注入。

${} 实现是sql语句的直接拼接,不做数据类型转换,需要自行判断数据类型。不能防止SQL注入。

是不是${}就没用了呢?不是的,有些情况下就必须使用${},举个例子:

在分表存储的情况下,我们从哪张表查询是不确定的,也就是说sql语句不能写死,表名是动态的,查询条件的固定的,这样:SELECT * FROM ${tableName} WHERE id = #{id}

CommonMapper.java

package cn.zto.mybatis.mapper;

import java.util.List;

import java.util.Map;

import org.apache.ibatis.annotations.Param;

public interface CommonMapper {

/**

* 根据表名查询表数据

*

* @param id

* @return

*/

public List<Map<String,Object>> queryByTableName(@Param("tableName")String tableName);

}

CommonMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE mapper

PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"

"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="cn.zto.mybatis.mapper.CommonMapper">

    <!--SELECT * FROM ${value} ${value}:value是mybatis默认的参数名-->

    <!--在接口中通过@Param来自定义参数名 -->

    <select id="queryByTableName" resultType="HashMap" parameterType="String">

        SELECT * FROM ${tableName}

    </select>

</mapper>

测试

@Test

public void queryByTableName() {

List<Map<String, Object>> queryByTableName = this.commonMapper.queryByTableName("tb_user");

for (Map<String, Object> map : queryByTableName) {

System.out.println(map);

}

}

总结:

#{} 占位符,用于参数传递,和参数名称无关。

${}用于SQL拼接。

resultMap – 映射复杂的结果对象

ResultMap是Mybatis中最重要最强大的元素,使用ResultMap可以解决两大问题:

POJO属性名和表结构字段名不一致的问题(有些情况下也不是标准的驼峰格式)

完成高级查询,比如说,一对一、一对多、多对多。

解决表字段名和属性名不一致的问题有两种方法:

1、如果是驼峰似的命名规则可以在Mybatis配置文件中设置<setting name="mapUnderscoreToCamelCase" value="true"/>解决

2、使用ResultMap解决。

3、还可以起别名.

SQL片段

我们在java代码中会将公用的一些代码提取出来需要的地方直接调用方法即可,在Mybatis也是有类似的概念,那就是SQL片段。

在Mybatis中使用<sql id="" />标签定义SQL片段,在需要的地方通过<include refid=""/>引用

例如:

<sql id="userColumns">id,user_name,password,name,age,sex,birthday,created,updated</sql>

<select id="queryUserById" resultMap="userResultMap" parameterType="Long">

    SELECT <include refid="userColumns"/> FROM tb_user WHERE id = #{id}

</select>

另外一种用法:

将所有的公用的SQL片段集中定义到一个Mapper.xml文件中,并将此Mapper.xml加入到全局配置文件mybatis-config.xml ,其他Mapper.xml文件如需引入,通过命名空间.id即可。

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE mapper

PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"

"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="my.common">

    <sql id="userColumns">id,user_name,password,name,age,sex,birthday,created,updated</sql>

</mapper>

加入全局配置文件mybatis-config.xml

<mappers>

    <mapper resource="UserMapper.xml" />

    <mapper resource="CommonMapper.xml" />

</mappers>

在mapper映射文件中引用:

<select id="queryUserById" resultMap="userResultMap" parameterType="Long">

    SELECT <include refid="my.common.userColumns"/> FROM tb_user WHERE id = #{id}

</select>

Mybatis学习总结().动态SQLMybatis缓存

MyBatis 的一个强大的特性之一通常是它的动态 SQL 能力。提供了OGNL表达式动态生成SQL的功能。动态SQL有:

1、if

2、choose, when, otherwise

3、where, set

4、foreach

if

需求1:查询男性用户,如果输入了姓名,进行模糊查找。

/**

* 测试动态sql

* 查询男性用户,如果输入了姓名,进行模糊查找。

* @param name

* @return

*/

public List<User> queryUserLikeName(@Param("name") String name);

<select id="queryUserLikeName" resultType="User">

    SELECT * FROM tb_user WHERE sex = 1

    <if test="name !=null and name != ''">

        AND name LIKE '%${name}%'

    </if>

</select>

测试1:

@Test

public void testQueryUserLikeName(){

List<User> users = this.userMapper.queryUserLikeName("张");

for (User user : users) {

System.out.println(user);

}

}

结果:

测试2:

@Test

public void testQueryUserLikeName(){

List<User> users = this.userMapper.queryUserLikeName(null);

for (User user : users) {

System.out.println(user);

}

}

结果:

choose, when, otherwise

需求2:查询男性用户,如果输入了姓名则按照姓名模糊查找,否则如果输入了年龄则按照年龄查找。

/**

* 查询男性用户,如果输入了姓名则按照姓名模糊查找,否则如果输入了年龄则按照年龄查找。

*

* @param name

* @param age

* @return

*/

public List<User> queryUserLikeNameAndAge(@Param("name") String name, @Param("age") Integer age);

<select id="queryUserLikeNameAndAge" resultType="User">

    SELECT * FROM tb_user WHERE sex = 1

    <choose>

        <when test="age !=null and age != ''">

            AND age < #{age}

        </when>

        <when test="name !=null and name != ''">

            AND name LIKE '%${name}%'

        </when>

    </choose>

</select>

测试:

@Test

public void testQueryUserLikeNameAndAge(){

List<User> users = this.userMapper.queryUserLikeNameAndAge("张",null);

for (User user : users) {

System.out.println(user);

}

}

结果:

where, set

作用:完成WHERE和SET关键字,并且处理SQL语句的中语法错误。

where测试:

需求3:查询所有用户,如果输入了姓名,进行模糊查找,如果输入了年龄则按照年龄查找。

/**

* 查询所有用户,如果输入了姓名,进行模糊查找,如果输入了年龄则按照年龄查找。

*

* @param name

* @return

*/

public List<User> queryUserLikeName2(@Param("name") String name, @Param("age") Integer age);

<select id="queryUserLikeName2" resultType="User">

    SELECT * FROM tb_user

    <where>

        <if test="name !=null and name != ''">

            AND name LIKE '%${name}%'

        </if>

        <if test="age !=null and age != ''">

            AND age < #{age}

        </if>

    </where>

</select>

测试:

@Test

public void testQueryUserLikeName2(){

List<User> users = this.userMapper.queryUserLikeName2(null,30);

for (User user : users) {

System.out.println(user);

}

}

结果:

SET测试:

更新数据

/**

* 更新user数据

*

* @param user

*/

public void updateUser2(User user);

<update id="updateUser2" parameterType="cn.zto.mybatis.pojo.User">

    UPDATE tb_user

    <set>

        <if test="userName != null and userName != ''">

            user_name = #{userName},

        </if>

        <if test="age != null and age != ''">

            age = #{age},

        </if>

        <if test="password != null and password != ''">

            password = #{password},

        </if>

    </set>

    WHERE

        id = #{id}

</update>

测试:

@Test

public void testUpdateUser2() {

User user = this.userMapper.queryUserById(2L);

user.setAge(35);

user.setPassword(null);

this.userMapper.updateUser2(user);

}

结果:

foreach

需求4:按照多个ID查询用户信息。

/**

* 按照多个ID查询用户信息。

*

* @param name

* @return

*/

public List<User> queryUserByIds(@Param("ids") List<Long> ids);

<select id="queryUserByIds" resultType="User">

    SELECT * FROM tb_user WHERE id IN

    <foreach collection="ids" item="id" open="(" close=")" separator=",">

        #{id}

    </foreach>

</select>

测试:

@Test

public void testQueryUserByIds(){

List<Long> ids = new ArrayList<Long>();

ids.add(1L);

ids.add(2L);

ids.add(3L);

List<User> users = this.userMapper.queryUserByIds(ids);

for (User user : users) {

System.out.println(user);

}

}

结果:

缓存:一级缓存

Mybatis的一级缓存的作用域是session,当openSession()后,如果执行相同的SQL(相同语句和参数),Mybatis不进行执行SQL,而是从缓存中命中返回。

原理:

Mybatis执行查询时首先去缓存区命中,如果命中直接返回,没有命中则执行SQL,从数据库中查询。

在Mybatis中一级缓存是默认开启,并且无法关闭。

测试一级缓存:

一级缓存满足条件:

1、 同一个session中

2、 相同的SQL和参数

使用session.clearCache()强制查询不缓存。

在执行insert、update、delete时会刷新缓存。

缓存:二级缓存

Mybatis的二级缓存的作用域是一个mapper的namespace,同一个namespace中查询sql可以从缓存中命中。

二级缓存是可以跨session的。

开启二级缓存:

在mapper.xml文件中加入 <cache /> 。

注意:在Mybatis-Config中有缓存的全局控制器(cacheEnabled),默认是开启的,所以无需手动开启。

也可以手动关闭二级缓存:

二级缓存关闭后,上面测试第二次查询将从数据库查询

在<cache />标签中还有其他一些参数,如下:

可以参考mybatis官方文档

Mybatis学习总结().Mybatis高级查询及延迟加载

 

Mybatis作为一个ORM框架,也对SQL的高级查询做了支持,下面我们学习Mybatis下的一对一、一对多、多对多的查询。

 

案例说明:
此案例的业务关系是用户、订单、订单详情、商品之间的关系,其中,
一个订单只能属于一个人。
一个订单可以有多个订单详情。
一个订单详情中包含一个商品信息。
 
它们的关系是:
 
订单和人是 一对一的关系。
订单和订单详情是 一对多 的关系。

订单和商品是 多对多的关系。

 

数据库关系图:


 

 

一对一查询

需求:一对一查询:查询订单,并且查询出下单人的信息。

 

SQL:   SELECT  o.*, u.user_name,u. NAME FROM tb_order o LEFT JOIN tb_user u ON o.user_id = u.id WHERE order_number = '20140921001'

第一种实现:

User.java

 

 

 

package cn.zto.mybatis.pojo;

 

 

import java.util.Date;

 

 

/**

 

 

*

 

 

* @ClassName: User

 

 

* @Description:对应用户表

 

 

* @author: xyc

 

 

* @date: 2017年2月11日 下午8:11:13

 

 

*

 

 

*/

 

 

public class User implements java.io.Serializable{

 

 

private static final long serialVersionUID = 1L;

 

 

private Long id;

 

 

// 用户名

 

 

private String userName;

 

 

// 密码

 

 

private String password;

 

 

// 姓名

 

 

private String name;

 

 

// 年龄

 

 

private Integer age;

 

 

// 性别,1男性,2女性

 

 

private Integer sex;

 

 

// 出生日期

 

 

private Date birthday;

 

 

// 创建时间

 

 

private Date created;

 

 

// 更新时间

 

 

private Date updated;

 

 

//getter And setter

 

 

@Override

 

 

public String toString() {

 

 

return "User [id=" + id + ", userName=" + userName + ", password=" + password + ", name=" + name

 

 

+ ", age=" + age + ", sex=" + sex + ", birthday=" + birthday + ", created=" + created

 

 

+ ", updated=" + updated + "]";

 

 

}

 

 

}

 


Order.java

 

 

 

 

package cn.zto.mybatis.pojo;

 

 

/**

 

 

*

 

 

* @ClassName: Order

 

 

* @Description:对应订单表

 

 

* @author: xyc

 

 

* @date: 2017年2月11日 下午8:22:24

 

 

*

 

 

*/

 

 

public class Order {

 

 

private Integer id;

 

 

private Long userId;

 

 

private String orderNumber;

 

 

//getter And setter

 

 

@Override

 

 

public String toString() {

 

 

return "Order [id=" + id + ", userId=" + userId + ", orderNumber=" + orderNumber + "]";

 

 

}

 

 

}

 

OrderUser.java

 

 

 

 

package cn.zto.mybatis.pojo;

 

 

/**

 

 

*

 

 

* @ClassName: OrderUser

 

 

* @Description: 此类用于补字段

 

 

* @author: xyc

 

 

* @date: 2017年2月11日 下午8:24:51

 

 

*

 

 

*/

 

 

public class OrderUser extends Order{

 

 

private String userName;

 

 

private String name;

 

 

//getter and setter

 

 

@Override

 

 

public String toString() {

 

 

return "OrderUser [userName=" + userName + ", name=" + name + "]";

 

 

}

 

 

}

 

 

OrderMapper.java

 

 

package cn.zto.mybatis.mapper;

 

 

import cn.zto.mybatis.pojo.OrderUser;

 

 

/**

 

 

 

* 测试高级查询

 

 

 

*/

 

 

 

public interface OrderMapper {

 

 

 

/**

 

 

 

* 查询订单,并且查询出下单人的信息。

 

 

 

* @param orderNumber

 

 

 

* @return

 

 

 

*/

 

 

 

public OrderUser queryOrderAndUserByOrderNumber(String orderNumber);

 

 

 

}

 

 


OrderMapper.xml

 

<?xml version="1.0" encoding="UTF-8" ?>

 

 

 

<!DOCTYPE mapper

 

 

PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"

 

 

"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

 

 

<mapper namespace="cn.zto.mybatis.mapper.OrderMapper">

 

 

<select id="queryOrderAndUserByOrderNumber" resultType="OrderUser">

 

 

SELECT

 

 

o.*,

 

 

u.user_name,

 

 

u.name

 

 

FROM

 

 

tb_order o

 

 

LEFT JOIN tb_user u ON o.user_id = u.id

 

 

WHERE order_number = #{orderNumber}

 

 

</select>

 

 

</mapper>

 

记得加入到全局配置文件中:

 

测试结果:



第二种实现:

核心思想:面向对象的思想,在Order对象中添加User对象。

 

 

 

package cn.zto.mybatis.pojo;

 

 

/**

 

 

*

 

 

* @ClassName: Order

 

 

* @Description:对应订单表

 

 

* @author: xyc

 

 

* @date: 2017年2月11日 下午8:33:12

 

 

*

 

 

*/

 

 

public class Order {

 

 

private Integer id;

 

 

private Long userId;

 

 

private String orderNumber;

 

 

private User user;

 

 

//getter And setter

 

 

}

 


Mapper接口:

 

 

 

 

/**

 

 

* 查询订单,并且查询出下单人的信息。

 

 

* @param orderNumber

 

 

* @return

 

 

*/

 

 

public Order queryOrderAndUserByOrderNumber2(String orderNumber);

 


Mapper映射文件

 

 

 

<!-- 在resultMap中,完成对象映射时,autoMapping默认为false,因此这里需要打开,否则有的属性关系无法对应 -->

 

 

<resultMap type="Order" id="orderResultMap" autoMapping="true">

 

 

<id column="id" property="id"/>

 

 

<!--

 

association:用户映射java对象

property: 对象中的属性名称

javaType:对象中的属性的类型 --><association property="user" javaType="User" autoMapping="true"><id column="user_id" property="id"/></association></resultMap>

<!-- 使用resultType不能完成自动映射,所以需要手动完成结果集的映射,需要使用resultMap实现。-->

<select id="queryOrderAndUserByOrderNumber2" resultMap="orderResultMap">SELECTo.*,u.user_name, u.nameFROMtb_order oLEFT JOIN tb_user u ON o.user_id = u.idWHERE order_number = #{orderNumber}</select>

 

测试:

 

 

 

 

 

 

 

@Test

 

 

public void testQueryOrderAndUserByOrderNumber2() {

 

 

Order order = this.orderMapper.queryOrderAndUserByOrderNumber2("20140921001");

 

 

System.out.println(order);

 

 

}

 

结果:

 




一对多查询

需求:查询订单,查询出下单人信息并且查询出订单详情。
 
SQL:

 

 

SELECT

 

 

o.*,

 

 

u.user_name,

 

 

u.name,

 

 

od.id detail_id,

 

 

od.item_id,

 

 

od.total_price

 

 

FROM

 

 

tb_order o

 

 

LEFT JOIN tb_user u ON o.user_id = u.id

 

 

LEFT JOIN tb_orderdetail od ON o.id = od.order_id

 

 

WHERE order_number = '20140921001'

 

 
Order.java

 

 

package cn.zto.mybatis.pojo;

 

 

import java.util.List;

 

 

/**

 

 

* 订单表

 

 

*

 

 

*/

 

 

public class Order {

 

 

private Integer id;

 

 

private Long userId;

 

 

private String orderNumber;

 

 

private User user;

 

 

//映射一对多查询的订单详情

 

 

private List<Orderdetail> orderdetails;

 

 

//getter And setter

 

 

@Override

 

 

public String toString() {

 

 

return "Order [id=" + id + ", userId=" + userId + ", orderNumber=" + orderNumber + ", user=" + user

 

 

+ ", orderdetails=" + orderdetails + "]";

 

 

}

 

 

}

 

Orderdetail.java

 

package cn.zto.mybatis.pojo;

 

 

/**

 

 

*

 

 

* @ClassName: Orderdetail

 

 

* @Description:订单详情

 

 

* @author: xyc

 

 

* @date: 2017年2月11日 下午9:42:28

 

 

*

 

 

*/

 

 

public class Orderdetail {

 

 

private Integer id;

 

 

private Double totalPrice;

 

 

private Integer status;

 

 

private Integer itemId;

 

 

private Item item;

 

 

//getter and setter

 

}

接口:

 

 

/**

 

 

* 查询订单,查询出下单人信息并且查询出订单详情。

 

 

*

 

 

* @param orderNumber

 

 

* @return

 

 

*/

 

 

public Order queryOrderAndUserAndOrderDetailByOrderNumber(String orderNumber);

 

 
Mapper映射文件:

 

 

<resultMap type="Order" id="orderUserOrderDetailresultMap" autoMapping="true">

 

 

<id column="id" property="id"/>

 

 

<!--

 

 

association:映射java对象

 

 

property: 对象中的属性名称

 

 

javaType:对象中的属性的类型

 

 

-->

 

 

<association property="user" javaType="User" autoMapping="true">

 

 

<id column="user_id" property="id"/>

 

 

</association>

 

 

<!--

 

 

collection:映射集合

 

 

javaType: 属性的java类型

 

 

ofType:集合中的对象的java类型

 

 

-->

 

 

<collection property="orderdetails" javaType="List" ofType="Orderdetail" autoMapping="true">

 

 

<id column="detail_id" property="id"/>

 

 

</collection>

 

 

</resultMap>

 

 

<select id="queryOrderAndUserAndOrderDetailByOrderNumber" resultMap="orderUserOrderDetailresultMap">

 

 

SELECT

 

 

o.*,

 

 

u.user_name,

 

 

u.name,

 

 

od.id detail_id,

 

 

od.item_id,

 

 

od.total_price

 

 

FROM

 

 

tb_order o

 

 

LEFT JOIN tb_user u ON o.user_id = u.id

 

 

LEFT JOIN tb_orderdetail od ON o.id = od.order_id

 

 

WHERE order_number = #{orderNumber}

 

 

</select>

 


测试:

 

 

@Test

 

 

public void testQueryOrderAndUserAndOrderDetailByOrderNumber() {

 

 

Order order = this.orderMapper.queryOrderAndUserAndOrderDetailByOrderNumber("20140921001");

 

 

System.out.println(order);

 

 

}

 

结果:
 

多对多查询

需求:查询订单,查询出下单人信息并且查询出订单详情中的商品数据
 
SQL:
 

SELECT

o.*,
u.user_name,

u.name,

od.id detail_id,

od.item_id,

od.total_price,

i.item_name,

i.item_price,

i.item_detail

FROM

tb_order o

LEFT JOIN tb_user u ON o.user_id = u.id

LEFT JOIN tb_orderdetail od ON o.id = od.order_id

LEFT JOIN tb_item i ON od.item_id = i.id

WHERE order_number = '20140921001'


Item.java
 

package cn.zto.mybatis.pojo;

/**

* 商品表

*/

public class Item {

private Integer id;

private String itemName;

private Float itemPrice;

private String itemDetail;

//getter and setter

}


Orderdetail.java

 

package cn.zto.mybatis.pojo;

/**
*
* @ClassName: Orderdetail
* @Description:订单详情
* @author: xyc
* @date: 2017年2月11日 下午9:42:28
*
*/
public class Orderdetail {
private Integer id;
private Double totalPrice;
private Integer status;
private Integer itemId;
private Item item;
//gette and setter
}


接口:

 

/**

* 多对多查询

* 查询订单,查询出下单人信息并且查询出订单详情中的商品数据。

* @param orderNumber

* @return

*/

public Order queryOrderAndUserAndOrderDetailAndItemByOrderNumber(String orderNumber);



Mapper映射:

 

<resultMap type="Order" id="orderUserOrderDetailItemResultMap" autoMapping="true">

<id column="id" property="id"/>
<!--
property: 对象中的属性名称
javaType:对象中的属性的类型
-->
<association property="user" javaType="User" autoMapping="true">
<id column="user_id" property="id"/>
</association>
<!-- 映射orderdetails -->
<collection property="orderdetails" javaType="List" ofType="Orderdetail" autoMapping="true">
<id property="id" column="detail_id"/>
<!--
映射Orderdetail中的Item对象
-->
<association property="item" javaType="Item" autoMapping="true">
<id property="id" column="item_id"/>
</association>
</collection>
</resultMap>
<select id="queryOrderAndUserAndOrderDetailAndItemByOrderNumber" resultMap="orderUserOrderDetailItemResultMap">
SELECT
o.*,
u.user_name,
u.name,
od.id detail_id,
od.item_id,
od.total_price,
i.item_name,
i.item_price,
i.item_detail
FROM
tb_order o
LEFT JOIN tb_user u ON o.user_id = u.id
LEFT JOIN tb_orderdetail od ON o.id = od.order_id
LEFT JOIN tb_item i ON od.item_id = i.id
WHERE order_number = #{orderNumber}
</select>


测试:

 

@Test

public void testQueryOrderAndUserAndOrderDetailAndItemByOrderNumber() {
Order order = this.orderMapper.queryOrderAndUserAndOrderDetailAndItemByOrderNumber("20140921001");

System.out.println(order);

}


结果:


ResultMap的继承  

通过上述可以发现,下面代码重用了,如何解决呢?

 

<!-- 在resultMap中,完成对象映射时,autoMapping默认为false,因此这里需要打开,否则有的属性关系无法对应 -->

<resultMap type="Order" id="orderResultMap" autoMapping="true">

<id column="id" property="id"/>

<!--

property: 对象中的属性名称

javaType:对象中的属性的类型

-->

<association property="user" javaType="User" autoMapping="true">

<id column="user_id" property="id"/>

</association>

</resultMap>


我们可以通过继承来完善

 

<resultMap type="Order" id="orderUserOrderDetailItemResultMap" extends="orderResultMap" autoMapping="true">

<!-- 映射orderdetails -->

<collection property="orderdetails" javaType="List" ofType="Orderdetail" autoMapping="true">

<id property="id" column="detail_id"/>

<!--

映射Orderdetail中的Item对象

-->

<association property="item" javaType="Item" autoMapping="true">

<id property="id" column="item_id"/>

</association>

</collection>

</resultMap>


extends的值为上面resultMap的id.

 

 

延迟加载

延迟加载的意义在于,虽然是关联查询,但不是及时将关联的数据查询出来,而且在需要的时候进行查询。


开启延迟加载:
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>


lazyLoadingEnabled:true使用延迟加载,false禁用延迟加载。默认为true
aggressiveLazyLoading:true启用时,当延迟加载开启时访问对象中一个懒对象属性时,将完全加载这个对象的所有懒对象属性。false,当延迟加载时,按需加载对象属性(即访问对象中一个懒对象属性,不会加载对象中其他的懒对象属性)。默认为true

 

①. 添加cglib支持

 

 

<dependency>

<groupId>cglib</groupId>

<artifactId>cglib</artifactId>

<version>3.1</version>

</dependency>

 

 

②.全局配置文件中开启延迟加载

 

 

<settings>

<!-- 开启驼峰映射 -->

<setting name="mapUnderscoreToCamelCase" value="true"/>

<!-- 二级缓存的全局开关 -->

<setting name="cacheEnabled" value="true"/>

<!-- 延迟加载的开关 -->

<setting name="lazyLoadingEnabled" value="true"/>

<!--

true启用时,当延迟加载开启时访问对象中一个懒对象属性时,将完全加载这个对象的所有懒对象属性。

false,当延迟加载时,按需加载对象属性(即访问对象中一个懒对象属性,不会加载对象中其他的懒对象属性)

-->

<setting name="aggressiveLazyLoading" value="false"/>

</settings>

 

 

③.编写接口:

 

 

/**

* 测试延迟加载
* 查询订单,并且查询出下单人的信息。
* @param orderNumber
* @return
*/

 

public Order lazyQueryOrderAndUserByOrderNumber(String orderNumber);


④.编写Mapper.xml

 


⑤.测试:

 

 

@Test

public void testLazyQueryOrderAndUserByOrderNumber() {
Order order = this.orderMapper.lazyQueryOrderAndUserByOrderNumber("20140921001");

User user = order.getUser();//触发延迟加载

System.out.println(user);

System.out.println(order);

}


结果:

 

Mybatis学习总结(七).Mybatis插件之分页插件

 

Mybatis的plugin实现原理

 
下图黑色部分为之前方式,红色部分为使用插件后
 

实现通用分页组件

如果想要将现有的select语句改为支持分页功能的查询语句该怎么做呢?最简单的一种做法就是将所有的select语句都加上limit来实现分页,这种做法有什么问题呢?


1、要改动的地方非常多,而且每个sql改动逻辑基本上一致;
2、DAO层的查询逻辑要改动,要在原来查询之后执行查询 SELECT count(1) from ….. 查询数据总条数。


有没有一种简便方法实现呢?

Mybatis提供了plugin机制,允许我们在Mybatis的原有处理流程上加入自己逻辑,所有我们就可以使用这种逻辑加上我们的分页逻辑,也就是实现拦截器。

Mybatis支持的拦截的接口有4个,Executor、ParameterHandler、ResultSetHandler、StatementHandler。
 


使用PageHelper实现分页

 
PageHelper实现了通用的分页查询,其支持的数据有,mysql、Oracle、DB2、PostgreSQL等主流的数据库。
该插件托管于github: https://github.com/pagehelper/Mybatis-PageHelper


参考《 Mybatis分页插件 - PageHelper.docx 》
 
①.导入依赖

 

<dependency>

<groupId>com.github.pagehelper</groupId>

<artifactId>pagehelper</artifactId>

<version>3.4.2</version>

</dependency>

<dependency>

<groupId>com.github.jsqlparser</groupId>

<artifactId>jsqlparser</artifactId>

<version>0.9.1</version>

</dependency>


②.在全局配置文件中配置插件

 

 

<plugins>

<!-- com.github.pagehelper为PageHelper类所在包名 -->
<plugin interceptor="com.github.pagehelper.PageHelper">
<!-- 方言 -->
<property name="dialect" value="mysql"/>
<!-- 该参数默认为false -->
<!-- 设置为true时,使用RowBounds分页会进行count查询 -->
<property name="rowBoundsWithCount" value="true"/>
</plugin>
</plugins>



③.编写接口

public List<User> queryUserListLikeName(@Param("name") String name);


④.编写映射文件

 

<select id="queryUserListLikeName" parameterType="String" resultType="User">

SELECT <include refid="my.common.userColumns"/> FROM tb_user WHERE name LIKE '%${name}%'

</select>


⑤.测试分页

 

@Test

public void testQueryUserListLikeName() {
//设置分页条件,Parameters:pageNum 页码pageSize 每页显示数量count 是否进行count查询
PageHelper.startPage(1, 3, true);
List<User> users = this.userMapper.queryUserListLikeName(null);
for (User user : users) {
System.out.println(user);
}
}


结果:

 
 
可以使用PageInfo 查看分页信息
 

@Test

public void testQueryUserListLikeName() {
//设置分页条件,Parameters:pageNum 页码pageSize 每页显示数量count 是否进行count查询

PageHelper.startPage(1, 3, true);

List<User> users = this.userMapper.queryUserListLikeName(null);

PageInfo<User> pageInfo = new PageInfo<User>(users);

//打印分页信息

System.out.println("数据总数:" + pageInfo.getTotal());

System.out.println("数据总页数:" + pageInfo.getPages());

System.out.println("最后一页:" + pageInfo.getLastPage());

for (User user : pageInfo.getList()) {

System.out.println(user);

}

}


PageInfo的方法
 
 
Mybatis批量增删改
 
批量删除
 
批量增加
 
批量修改

 

Mybatis和Spring的整合

目录结构:

 

①.引入依赖pom.xml

 

 

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

 

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

 

<modelVersion>4.0.0</modelVersion>

 

<parent>

 

<groupId>cn.zto.parent</groupId>

 

<artifactId>zto-parent</artifactId>

 

<version>0.0.1-SNAPSHOT</version>

 

</parent>

 

<groupId>cn.zto.mybatis</groupId>

 

<artifactId>zto-mybatis-spring</artifactId>

 

<version>1.0.0-SNAPSHOT</version>

 

<dependencies>

 

<!-- 单元测试 -->

 

<dependency>

 

<groupId>junit</groupId>

 

<artifactId>junit</artifactId>

 

<scope>test</scope>

 

</dependency>

 

<!-- Mybatis -->

 

<dependency>

 

<groupId>org.mybatis</groupId>

 

<artifactId>mybatis</artifactId>

 

</dependency>

 

<!-- MySql -->

 

<dependency>

 

<groupId>mysql</groupId>

 

<artifactId>mysql-connector-java</artifactId>

 

</dependency>

 

<dependency>

 

<groupId>org.slf4j</groupId>

 

<artifactId>slf4j-log4j12</artifactId>

 

</dependency>

 

<dependency>

 

<groupId>cglib</groupId>

 

<artifactId>cglib</artifactId>

 

<version>3.1</version>

 

</dependency>

 

<dependency>

 

<groupId>com.github.pagehelper</groupId>

 

<artifactId>pagehelper</artifactId>

 

<version>3.7.5</version>

 

</dependency>

 

<dependency>

 

<groupId>com.github.jsqlparser</groupId>

 

<artifactId>jsqlparser</artifactId>

 

<version>0.9.1</version>

 

</dependency>

 

<!-- 整合 -->

 

<dependency>

 

<groupId>org.springframework</groupId>

 

<artifactId>spring-context</artifactId>

 

</dependency>

 

<dependency>

 

<groupId>org.mybatis</groupId>

 

<artifactId>mybatis-spring</artifactId>

 

</dependency>

 

<!-- 连接池 -->

 

<dependency>

 

<groupId>com.jolbox</groupId>

 

<artifactId>bonecp-spring</artifactId>

 

<version>0.8.0.RELEASE</version>

 

</dependency>

 

<dependency>

 

<groupId>org.springframework</groupId>

 

<artifactId>spring-jdbc</artifactId>

 

</dependency>

 

<dependency>

 

<groupId>org.springframework</groupId>

 

<artifactId>spring-aspects</artifactId>

 

</dependency>

 

</dependencies>

 

</project>

②.编写实体User、Mapper接口、Mapper映射文件

 

User.java

 

 

 

package cn.zto.mybatis.pojo;

 

import java.util.Date;

 

public class User implements java.io.Serializable{

 

private static final long serialVersionUID = -5846970261372764303L;

 

private Long id;

 

// 用户名

 

private String userName;

 

// 密码

 

private String password;

 

// 姓名

 

private String name;

 

// 年龄

 

private Integer age;

 

// 性别,1男性,2女性

 

private Integer sex;

 

// 出生日期

 

private Date birthday;

 

// 创建时间

 

private Date created;

 

// 更新时间

 

private Date updated;

 

//getter and setter

 

@Override

 

public String toString() {

 

return "User [id=" + id + ", userName=" + userName + ", password=" + password + ", name=" + name

 

+ ", age=" + age + ", sex=" + sex + ", birthday=" + birthday + ", created=" + created

 

+ ", updated=" + updated + "]";

 

}

 

}

 

UserMapper.java

 

 

 

package cn.zto.mybatis.mapper;

 

import org.apache.ibatis.annotations.Param;

 

import cn.zto.mybatis.pojo.User;

 

public interface UserMapper {

 

/**

 

* 根据id查询用户信息

 

*

 

* @param id

 

* @return

 

*/

 

public User queryUserById(@Param("id") Long id);

 

}

 

UserMapper.xml

 

 

 

<?xml version="1.0" encoding="UTF-8" ?>

 

<!DOCTYPE mapper

 

PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"

 

"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

 

<mapper namespace="cn.zto.mybatis.mapper.UserMapper">

 

<select id="queryUserById" parameterType="Long" resultType="User">

 

SELECT * FROM tb_user WHERE id = #{id}

 

</select>

 

</mapper>

 

③.配置数据源

 

jdbc.properties

 

 

jdbc.driver=com.mysql.jdbc.Driver

 

jdbc.url=jdbc:mysql://127.0.0.1:3306/mybatis?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true

 

jdbc.username=root

 

jdbc.password=123456

 

 

applicationContext.xml

 

 

<?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:p="http://www.springframework.org/schema/p"

 

xmlns:context="http://www.springframework.org/schema/context"

 

xmlns:mvc="http://www.springframework.org/schema/mvc"

 

xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd

 

http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd

 

http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

 

<!-- 使用spring自带的占位符替换功能 -->

 

<bean

 

class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">

 

<!-- 允许JVM参数覆盖 -->

 

<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />

 

<!-- 忽略没有找到的资源文件 -->

 

<property name="ignoreResourceNotFound" value="true" />

 

<!-- 配置资源文件 -->

 

<property name="locations">

 

<list>

 

<value>classpath:jdbc.properties</value>

 

</list>

 

</property>

 

</bean>

 

<bean id="dataSource" class="com.jolbox.bonecp.BoneCPDataSource"

 

destroy-method="close">

 

<!-- 数据库驱动 -->

 

<property name="driverClass" value="${jdbc.driver}" />

 

<!-- 相应驱动的jdbcUrl -->

 

<property name="jdbcUrl" value="${jdbc.url}" />

 

<!-- 数据库的用户名 -->

 

<property name="username" value="${jdbc.username}" />

 

<!-- 数据库的密码 -->

 

<property name="password" value="${jdbc.password}" />

 

<!-- 检查数据库连接池中空闲连接的间隔时间,单位是分,默认值:240,如果要取消则设置为0 -->

 

<property name="idleConnectionTestPeriod" value="60" />

 

<!-- 连接池中未使用的链接最大存活时间,单位是分,默认值:60,如果要永远存活设置为0 -->

 

<property name="idleMaxAge" value="30" />

 

<!-- 每个分区最大的连接数 -->

 

<property name="maxConnectionsPerPartition" value="150" />

 

<!-- 每个分区最小的连接数 -->

 

<property name="minConnectionsPerPartition" value="5" />

 

</bean>

 

</beans>

 

④.配置SqlSessionFactory

这里使用的并不是SqlSessionFactoryBuilder,而是使用的Mybatis-spring整合jar中的org.mybatis.spring.SqlSessionFactoryBean,并且通过configLocation配置Mybatis的配置文件。

 

 

<?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:p="http://www.springframework.org/schema/p"

 

xmlns:context="http://www.springframework.org/schema/context"

 

xmlns:mvc="http://www.springframework.org/schema/mvc"

 

xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd

 

http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd

 

http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

 

<!-- 定义Mybatis的SqlSessionFactory -->

 

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">

 

<!-- 定义数据源 -->

 

<property name="dataSource" ref="dataSource" />

 

<!-- 指定mybatis全局配置文件 -->

 

<property name="configLocation" value="classpath:mybatis-config.xml"></property>

 

</bean>

 

</beans>

 

⑤.配置mybatis全局文件

 

mybatis-config.xml

 

 

<?xml version="1.0" encoding="UTF-8" ?>

 

<!DOCTYPE configuration

 

PUBLIC "-//mybatis.org//DTD Config 3.0//EN"

 

"http://mybatis.org/dtd/mybatis-3-config.dtd">

 

<configuration>

 

<settings>

 

<!-- 开启驼峰映射 -->

 

<setting name="mapUnderscoreToCamelCase" value="true"/>

 

</settings>

 

<typeAliases>

 

<!-- <typeAlias type="cn.zto.mybatis.pojo.User" alias="User"/> -->

 

<!--

 

配置扫描包,更适合企业开发

 

-->

 

<package name="cn.zto.mybatis.pojo"/>

 

</typeAliases>

 

<mappers>

 

<mapper resource="UserMapper.xml" />

 

</mappers>

 

</configuration>

 

⑥.添加日志

log4j.properties

 

 

log4j.rootLogger=DEBUG,A1

 

log4j.logger.org.mybatis = DEBUG

 

log4j.appender.A1=org.apache.log4j.ConsoleAppender

 

log4j.appender.A1.layout=org.apache.log4j.PatternLayout

 

log4j.appender.A1.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c]-[%p] %m%n

 

 

⑦.测试:

 

 

package cn.zto.mybatis.mapper;

 

import org.apache.ibatis.session.SqlSession;

 

import org.apache.ibatis.session.SqlSessionFactory;

 

import org.junit.Before;

 

import org.junit.Test;

 

import org.springframework.context.ApplicationContext;

 

import org.springframework.context.support.ClassPathXmlApplicationContext;

 

import cn.zto.mybatis.pojo.User;

 

public class UserMapperTest {

 

private UserMapper userMapper;

 

/**

 

* @throws Exception

 

*/

 

@Before

 

public void setUp() throws Exception {

 

// 初始化SPring容器

 

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml",

 

"applicationContext-mybatis.xml");

 

// 从容器中获取SqlSessionFactory

 

SqlSessionFactory sqlSessionFactory = applicationContext.getBean(SqlSessionFactory.class);

 

SqlSession sqlSession = sqlSessionFactory.openSession(true);

 

this.userMapper = sqlSession.getMapper(UserMapper.class);

 

}

 

@Test

 

public void testQueryUserById() {

 

User user = this.userMapper.queryUserById(1L);

 

System.out.println(user);

 

}

 

}

 

结果:

 

 

ok,mybatis已经和spring整合起来了。

但是发现 每次还是要先获取SqlSessionFactory,然后获取到session,之后从session中获取Mapper

如果能从容器中直接获取到Mapper就更好了

 

定义Mapper

在applicationContext-mybatis.xml中添加

 

 

<?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:p="http://www.springframework.org/schema/p"

 

xmlns:context="http://www.springframework.org/schema/context"

 

xmlns:mvc="http://www.springframework.org/schema/mvc"

 

xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd

 

http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd

 

http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

 

<!-- 定义Mybatis的SqlSessionFactory -->

 

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">

 

<!-- 定义数据源 -->

 

<property name="dataSource" ref="dataSource" />

 

<!-- 指定mybatis全局配置文件 -->

 

<property name="configLocation" value="classpath:mybatis-config.xml"></property>

 

</bean>

 

<!-- 定义Mapper -->

 

<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">

 

<!-- 指定Mapper接口的地址 -->

 

<property name="mapperInterface" value="cn.zto.mybatis.mapper.UserMapper" />

 

<!-- sqlSessionFactory依赖 -->

 

<property name="sqlSessionFactory" ref="sqlSessionFactory" />

 

</bean>

 

</beans>



 

 

测试:

 

 

package cn.zto.mybatis.mapper;

 

import org.junit.Before;

 

import org.junit.Test;

 

import org.springframework.context.ApplicationContext;

 

import org.springframework.context.support.ClassPathXmlApplicationContext;

 

import cn.zto.mybatis.pojo.User;

 

public class UserMapperTest {

 

private UserMapper userMapper;

 

/**

 

* @throws Exception

 

*/

 

@Before

 

public void setUp() throws Exception {

 

// 初始化SPring容器

 

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml",

 

"applicationContext-mybatis.xml");

 

// 从容器中获取SqlSessionFactory

 

// SqlSessionFactory sqlSessionFactory =

 

// applicationContext.getBean(SqlSessionFactory.class);

 

// SqlSession sqlSession = sqlSessionFactory.openSession(true);

 

// this.userMapper = sqlSession.getMapper(UserMapper.class);

 

this.userMapper = applicationContext.getBean(UserMapper.class);

 

}

 

@Test

 

public void testQueryUserById() {

 

User user = this.userMapper.queryUserById(1L);

 

System.out.println(user);

 

}

 

}

 

上面还是有点问题,如果有多个Mapper映射文件,是不是要配置多个MapperFactotyBean呢?

 

这里可以配置Mapper接口的自动扫描器

配置Mapper接口的自动扫描器

我们没有必要一个一个的在spring配置文件中配置Mapper接口,Mybatis的Spring整合包中提供了更高级的方式,mapper接口扫描器,org.mybatis.spring.mapper.MapperScannerConfigurer

在applicationContext-mybatis.xml中添加

 

 

<?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:p="http://www.springframework.org/schema/p"

 

xmlns:context="http://www.springframework.org/schema/context"

 

xmlns:mvc="http://www.springframework.org/schema/mvc"

 

xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd

 

http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd

 

http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

 

<!-- 定义Mybatis的SqlSessionFactory -->

 

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">

 

<!-- 定义数据源 -->

 

<property name="dataSource" ref="dataSource" />

 

<!-- 指定mybatis全局配置文件 -->

 

<property name="configLocation" value="classpath:mybatis-config.xml"></property>

 

</bean>

 

<!-- 定义Mapper -->

 

<!-- <bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">

 

指定Mapper接口的地址

 

<property name="mapperInterface" value="cn.zto.mybatis.mapper.UserMapper" />

 

sqlSessionFactory依赖

 

<property name="sqlSessionFactory" ref="sqlSessionFactory" />

 

</bean> -->

 

<!-- 定义Mapper接口扫描器 -->

 

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">

 

<property name="basePackage" value="cn.zto.mybatis.mapper" />

 

</bean>

 

</beans>

 

问题?多个包怎么配置?

 

参考源码可以用分隔符分割

 

 

使用通配符配置mapper.xml文件

 

 

<!-- 定义Mybatis的SqlSessionFactory -->

 

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">

 

<!-- 定义数据源 -->

 

<property name="dataSource" ref="dataSource" />

 

<!-- 指定mybatis全局配置文件 -->

 

<property name="configLocation" value="classpath:mybatis-config.xml"></property>

 

<!-- 扫描mappers目录以及子目录下的所有xml文件 -->

 

<property name="mapperLocations" value="classpath:mappers/**/*.xml" />

 

</bean>

 

使用mapperLocations扫描到mapper文件下的所有xml,同时移除mybatis全局配置文件中的mapper配置

 

 

继续简化Mybatis全局配置文件,将别名包配置到也配置到spring中,同时将全局配置文件中的别名配置移除

 

 

<!-- 定义Mybatis的SqlSessionFactory -->

 

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">

 

<!-- 定义数据源 -->

 

<property name="dataSource" ref="dataSource" />

 

<!-- 指定mybatis全局配置文件 -->

 

<property name="configLocation" value="classpath:mybatis-config.xml"></property>

 

<!-- 扫描mappers目录以及子目录下的所有xml文件 -->

 

<property name="mapperLocations" value="classpath:mappers/**/*.xml" />

 

<!-- 别名扫描包 -->

 

<property name="typeAliasesPackage" value="cn.zto.mybatis.pojo"/>

 

</bean>

 

最终mybatis全局配置文件下剩下驼峰配置了

 

 

 

<?xml version="1.0" encoding="UTF-8" ?>

 

<!DOCTYPE configuration

 

PUBLIC "-//mybatis.org//DTD Config 3.0//EN"

 

"http://mybatis.org/dtd/mybatis-3-config.dtd">

 

<configuration>

 

<settings>

 

<!-- 开启驼峰映射 -->

 

<setting name="mapUnderscoreToCamelCase" value="true"/>

 

</settings>

 

<!-- <typeAliases>

 

<typeAlias type="cn.zto.mybatis.pojo.User" alias="User"/>

 

配置扫描包,更适合企业开发

 

<package name="cn.zto.mybatis.pojo"/>

 

</typeAliases> -->

 

<!-- <mappers>

 

<mapper resource="UserMapper.xml" />

 

</mappers> -->

 

</configuration>

 

applicationContext-mybatis.xml

 

 

 

<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 定义Mybatis的SqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 定义数据源 -->
<property name="dataSource" ref="dataSource" />
<!-- 指定mybatis全局配置文件 -->
<property name="configLocation" value="classpath:mybatis-config.xml"></property>
<!-- 扫描mappers目录以及子目录下的所有xml文件 -->
<property name="mapperLocations" value="classpath:mappers/**/*.xml" />
<!-- 别名扫描包 -->
<property name="typeAliasesPackage" value="cn.zto.mybatis.pojo"/>
</bean>
<!-- 定义Mapper -->
<!-- <bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
指定Mapper接口的地址
<property name="mapperInterface" value="cn.zto.mybatis.mapper.UserMapper" />
sqlSessionFactory依赖
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean> -->
<!-- 定义Mapper接口扫描器 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="cn.zto.mybatis.mapper" />
</bean>
</beans>



事务管理

Mybatis和spring整合后的事务管理是由Spring管理的,事务管理器依然使用jdbc的事务管理器,org.springframework.jdbc.datasource.DataSourceTransactionManager。 

 

posted @ 2018-10-19 14:58  CharyGao  阅读(297)  评论(0编辑  收藏  举报