手把手学Java之Mybatis

小感悟:

    自学Java也有一年了,基本上都是学习基础的教程,Java水很深,前面学习新知识后面忘了老知识,我也不知道关于Java中的东西反反复复的敲了多少次。大学同学在某个培训机构里面培训了仅仅三个月就去工作了,笔者和培训后的同学交流后感觉技术不过如此。Java的学习道路很是艰难,虽然我毕业后没能去从事软件开发,但是我想用时间来沉淀一下自己的技术,今天我们就来谈谈Mybatis技术。

使用技术:Maven+Mybatis

开发工具:IDEA

1 HelloWorld

创建Maven项目并且在pom.xml文件中导入Mybatis依赖

<dependency>

<groupId>org.mybatis</groupId>

<artifactId>mybatis</artifactId>

<version>RELEASE</version>

</dependency>

数据库中创建一个book表

CREATE TABLE `book` (

  `id` int(10) NOT NULL AUTO_INCREMENT,

  `name` varchar(50) DEFAULT NULL,

  `author` varchar(50) DEFAULT NULL,

  PRIMARY KEY (`id`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

创建实体类并且生成set和get以及toString方法

book实体类

mybatis参考文档中复制约束文件(Mybatis官方参考网址)

http://www.mybatis.org/mybatis-3/zh/getting-started.html

参考官方文档创建mybatis核心配置文件

mybatis核心配置文件

pom.xml文件中引入Mysql驱动依赖

<dependency>

<groupId>mysql</groupId>

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

<version>RELEASE</version>

</dependency>

创建数据库配置文件db.properties

db.driver=com.mysql.jdbc.Driver

db.url=jdbc:mysql:///test_mybatis

db.username=root

db.password=xxxxxxxxxxx

在mybatis核心配置文件中引入数据库配置文件

mybatis核心配置文件中引入数据库配置

将${}里面的内容更改为${db.properties}

创建mapper包并且在该包下面创建接口和xml文件

Mapper

BookMapper接口中添加内容为

public interface BookMapper {

int addBook(Book book);

}

BookMapper.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="com.mapper.BookMapper">

<insert id="addBook">

insert into book set name="浅谈mybatis",author="孤芳不自赏";

</insert>

</mapper>

核心配置文件中引入mapper.xml文件

mybatis核心配置文件中引入mapper.xml文件

创建测试类

public class test_mybatis {

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

//读取mybatis核心配置文件,抛出异常

        InputStream r = Resources.getResourceAsStream("mybatis-conf.xml");

//创建sqlSession工厂

        SqlSessionFactory sqf =new SqlSessionFactoryBuilder().build(r);

//通过工厂来获取session对象

        SqlSession session = sqf.openSession();

//通过session来进行响应的crud操作

/**

* 添加操作

*/

        int i = session.insert("addBook");

session.commit();

if (i>0){

System.out.println("添加成功!");

}else{

System.out.println("添加失败!");

}

session.close();

}

}

此时运行会报如下错误(未发现核心配置文件)

Cause: java.io.IOException: Could not find resource com/mapper/BookMapper.xml

pom.xml文件中添加内容如下

<build>

<resources>

<resource>

<directory>src/main/java</directory>

<includes>

<include>**/*.xml</include>

</includes>

</resource>

<resource>

<directory>src/main/resources</directory>

</resource>

</resources>

</build>

此时运行还会报错

You must configure either the server or JDBC driver (via the serverTimezone configuration property) to use a more specifc time zone value if you want to utilize time zone support.

在db.properties中的url后面添加内容为

?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC

db.properties

然后运行结果:

成功运行控制台打印

数据库表中

添加成功后的结果

此时已经成功的用Mybatis书写了一个HelloWorld程序!

本节视频教程:
本节代码源码资料:



2 日志打印

pom.xml文件中引入log4j依赖

<dependency>

<groupId>log4j</groupId>

<artifactId>log4j</artifactId>

<version>RELEASE</version>

</dependency>

resources下面创建log4j.properties文件,且里面添加如下内容

log4j.rootLogger= DEBUG,stdout

log4j.logger.org.mybatis=DEBUG

###输出信息到控制抬 ###

log4j.appender.stdout= org.apache.log4j.ConsoleAppender

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

log4j.appender.stdout.layout.ConversionPattern =%C %p %m %n

此时在运行我们的项目就会发现控制台多出

控制台打印sql语句



3 参数传递

BookMapper.xml文件中添加

<insert id="addBook" parameterType="com.model.Book">

insert into book set name=#{name},author=#{author};

</insert>

测试类中

public class test_mybatis {

private SqlSessionsession;

@Before

    public void before()throws IOException {

//读取mybatis核心配置文件,抛出异常

        InputStream r = Resources.getResourceAsStream("mybatis-conf.xml");

//创建sqlSession工厂

        SqlSessionFactory sqf =new SqlSessionFactoryBuilder().build(r);

//通过工厂来获取session对象

        session = sqf.openSession();

//通过session来进行响应的crud操作

    }

@After

    public void after(){

session.close();

}

@Test

    public void test1(){

Book book =new Book();

book.setName("浅谈mybatis");

book.setAuthor("孤芳不自赏");

int i =session.insert("addBook",book);

session.commit();

if (i>0) {

System.out.println("添加成功");

}else{

System.out.println("添加失败");

}

}

}



4 自定义Dao方法

之前当我们想实现crud操作时候都是调用seesion里面的方法,现在我们自己来创建自己的方法。

之前实现curd都是调用sessio中的

在BookMapper中添加接口

public interface BookMapper {

int addBook(Book book);

int updateBook(Book book);

int deleteBook();

}

此时我们在测试类里面就可以调用自己的接口了

调用自己书写的Mapper接口

BookMapper.xml文件中添加更新方法

<insert id="updateBook" parameterType="com.model.Book">

update book set author=#{author} where id=#{id}

</insert>

测试类中

@Test

public void test2(){

BookMapper mapper =session.getMapper(BookMapper.class);

Book book =new Book();

book.setId(30);

book.setAuthor("MybatisBoy");

int i = mapper.updateBook(book);

if (i>0) {

System.out.println("更新成功");

}else{

System.out.println("更新失败");

}

session.commit();

}

更新结果为

更新数据库结果

5 简化mybatis配置

5.1创建mapper.xml模板


创建mapper.xml模板


添加内容

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"

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

<mapper namespace="#[[$Title$]]#">

</mapper>

使用刚刚创建好的模板来创建一个testMapper.xml


创建一个testMppaer


创建的后的结果

声明:还可以用来简化db.properties配置文件哦!自己动手尝试一下吧。

5.2 给类起别名

细心的同学会发现我们写插入语句时候的parameterType类型往往是类的路径,能不能进一步简化呢?答案是当然可以了。


简化前
简化后


核心配置文件中配置

虽然简化了一个类,但是当类多的时候每次都要在配置文件中配置这样依然很繁琐。于是可以这样配置。

给model下的所有类起别名

每次添加一个mapper.xml都要在核心配置文件中引入,这样依然很麻烦。

简化前


简化后

6  类型转换

mybatis中基本的类型都能进行转换。加入我想将Java中的一个List集合的数据保存都数据库中varchar类型的字段中那么如何保存呢?

给book表添加字段

book表中添加favorties字段

实体类中添加字段并且生成set和get方法

实体类中添加favorities字段

自己创建类型转换类并且实现TypeHandler接口

配置类上面要添加注解

@MappedJdbcTypes(JdbcType.VARBINARY)

@MappedTypes(List.class)

public class MyTypeHandlerimplements TypeHandler> {

public void setParameter(PreparedStatement preparedStatement,int i, List strings, JdbcType jdbcType)throws SQLException {

/**

* 在这个里面将List集合中的数据全部处理为字符串

* i 插入的第几个位置

* strings为List中的数据

*/

 StringBuffer sb =new StringBuffer();

for (String s : strings) {

sb.append(s).append(",");

}

preparedStatement.setString(i,sb.toString());

}

public List getResult(ResultSet resultSet, String s)throws SQLException {

return null;

}

public List getResult(ResultSet resultSet,int i)throws SQLException {

return null;

}

public List getResult(CallableStatement callableStatement,int i)throws SQLException {

return null;

}

}

mapper.xml文件中添加

<insert id="addBook" parameterType="book"> insert into book set name=#{name},favorities=#{favorities,typeHandler=com.config.MyTypeHandler}</insert>

测试类中

@Test

public void test1(){

List list =new ArrayList();

list.add("Java");

list.add("C");

list.add("C++");

list.add("Objc++");

Book book =new Book();

book.setName("浅谈mybatis");

book.setAuthor("孤芳不自赏");

book.setFavorities(list);

int i =session.insert("addBook",book);

session.commit();

if (i>0) {

System.out.println("添加成功");

}else{

System.out.println("添加失败");

}

}

控制台打印的 sql为

添加list集合

数据库中

数据库中的结果

我们成功的添加之后那么如何获取?

mapper中添加接口

List<Book> getAllBooks();

mapper.xml文件中查询全部

<select id="getAllBooks" resultType="book">

select* from book;

</select>

测试类中书写

@Test

public void test_getAllBooks(){

BookMapper mapper =session.getMapper(BookMapper.class);

List list = mapper.getAllBooks();

if (list !=null) {

for (Book book : list) {

System.out.println(book);

}

}

}

经过一番准备后发现测试结果是这样的.

查询全部的测试结果

emmm.....此时心里是不是凉凉~~

好了开始放大招了!!

核心配置类中配置别名

配置自定义类的别名

将字符串类打回List原形

将字符串打回List集合原形

此时在执行结果为

配置后的查询结果

7 $和#有啥区别

这个问题相比参加过Java面试的时候都遇到过,下面直接来看

7.1使用$

接口

Book getBookById(Integer id);

Mapper.xml配置文件中

<select id="getBookById" resultType="book">

select* from book where id=${id}

</select>

测试类为

@Test

  public void test_getOneBook(){

BookMapper mapper =session.getMapper(BookMapper.class);

Book book = mapper.getBookById(29);

if (book !=null) {

System.out.println(book);

}

}

}

控制台sql为

使用$的结果

此处的Id为Integer类型,假如为String类型

接口中

Book getBookById(String id);

Mapper.xml配置文件中

<select id="getBookById" resultType="book" parameterType="string">

select* from book where id=${id}

</select>

测试类

@Test

  public void test_getOneBook(){

BookMapper mapper =session.getMapper(BookMapper.class);

Book book = mapper.getBookById("29");

if (book !=null) {

System.out.println(book);

}

}

}

控制台sql为

id为String类型时候(前)

emm....貌似没看出来变化啊!!

But~~更该测试类

@Test

  public void test_getOneBook(){

BookMapper mapper =session.getMapper(BookMapper.class);

Book book = mapper.getBookById("29 or id in (30,31)");

if (book !=null) {

System.out.println(book);

}

}

再次运行

id为String类型时候(后)

且不说返回的结果如何获取,是不是发生了sql注入???!sql注入多可怕!!


7.2 使用#

将$更改为#

<select id="getBookById" resultType="book" parameterType="string">

select* from book where id=#{id}

</select>

使用#

说了这么就是让大家对#和$又更深的认识,不懂的还可以参考以下博客:Mybatis中的#和$到底有啥区别


8 传递其他值

之前传递的要么是Integer类型要么是String类型要么是对象类型 。如何传递一个Map对象呢?

添加接口

int insertBook(HashMap map);

测试类中

@Test

public void test_insertOneBook(){

HashMap map =new HashMap();

map.put("name","浅谈JavaEE");

map.put("author","孤芳不自赏");

BookMapper mapper =session.getMapper(BookMapper.class);

int i = mapper.insertBook(map);

session.commit();

}

mapper.xml文件中

<insert id="insertBook" parameterType="HashMap">

insert into book set name=#{name},author=#{author}

</insert>

控制台中

添加map类型

数据中

数据库添加的字段

如何取出来,接口

HashMap<String,String> getBookByIdResultMap(Integer uid);

核心配置文件中

<select id="getBookByIdResultMap" resultType="java.util.HashMap">

select* from book where id=#{uid}

</select>

测试类中

@Test

  public void test_insertOneBook(){

//      HashMap map = new HashMap();

//      map.put("name","浅谈JavaEE");

//      map.put("author","孤芳不自赏");

      BookMapper mapper =session.getMapper(BookMapper.class);

//      int i = mapper.insertBook(map);

//      session.commit();

      HashMap map = mapper.getBookByIdResultMap(34);

System.out.println(map);

}

}

对比观察一下,map返回的是集合,之前的返回的是对象

        {author=孤芳不自赏, name=浅谈JavaEE, id=34}  //map集合返回 

Book{author=孤芳不自赏, name=浅谈JavaEE, id=34}  //之前的返回


9 resultMap

9.1通过起别名解决

问题:当数据库中的字段和java实体类中的字段不对应时候,当自动查询时候就无法映射上,此时可以通过给字段其别名的方式来实现,但是每次都要给字段起别名就很麻烦,可以通过抽出该别名字段的方式,但是使用resultMap能很好的解决这一问题。

创建author表

author表

CREATE TABLE `author` (

  `id` int(10) NOT NULL AUTO_INCREMENT,

  `author_name` varchar(50) DEFAULT NULL,

  `book_name` varchar(50) DEFAULT NULL,

  PRIMARY KEY (`id`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

创建实体类(注意实体类的属性名和数据库的字段不对应)

author实体类

Mapper配置文件中

mapper配置文件

    测试类中

测试类

结果有两个为Null

测试结果

通过起别名解决

起别名后的结果

9.2通过resultMap解决

配置文件中书写

<resultMap id="MyResultMap" type="com.model.Author">

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

<result column="author_name" property="authorName"></result>

<result column="book_name" property="bookName"></result>

</resultMap>

<select id="getAuthorList" resultMap="MyResultMap">

select* from author;

</select>

其中

column对应的是数据库中的字段

property对应的是实体类中的字段

测试结果和上面的一样

resultMap原理

9.3 传递多个参数

当我们想存储bookName和AuthorName这两个字段到数据库表中的时候,但是又不想通过传递实体类来封装,此时该怎么办?

接口中

int insertAuthor(String bookName,String authorName);

xml文件中

<insert id="insertAuthor" parameterType="string">

insert into author set book_name=#{bookName},author_name=#{authorName}

</insert>

测试

@Test

public void test4(){

AuthorMapper mapper =session.getMapper(AuthorMapper.class);

int i = mapper.insertAuthor("JavaEE","孤芳不自赏");

session.commit();

}

控制台报错

org.apache.ibatis.binding.BindingException: Parameter 'bookName' not found

为了解决这个问题:@Param横空出世

将接口改为

int insertAuthor(@Param("bookName") String bookName, @Param("authorName") String authorName);

此时在运行就可以插入成功了。添加上注解之后就连parameterType也可以不写了。

最终的mapper为

<insert id="insertAuthor" >

insert into author set book_name=#{bookName},author_name=#{authorName}

</insert>

@Param的意思就是将bookName注入到mybatis中,当在配置文件中使用的时候,这个名字是认识的,所以就不会报找不到该名字。


10 动态sql

在mysql中个人感觉使用频率最高的还是动态sql,动态sql顾名思义,就是sql语句是可以动态的改变的呗。稍微好听的称呼是:动态sql就是可以在sql语句中拼接或组装sql。

>>foreach

10.1使用foreach根据传递数组id集合进行查询

添加接口

List getAuthorByIds(@Param("ids") Long[] id);

配置文件中

<select id="getAuthorByIds" resultMap="MyResultMap">

select* from author where id in(

<foreach collection="ids" item="id" separator=",">

#{id}

</foreach>

)

</select>

测试类中

@Test

public void test5(){

AuthorMapper mapper =session.getMapper(AuthorMapper.class);

Long[] ids={1L,5L,6L};

List list = mapper.getAuthorByIds(ids);

for (Author author : list) {

System.out.println(author);

}

}

测试结果

测试结果

语句可以进一步的简化

<select id="getAuthorByIds" resultMap="MyResultMap">

select* from author where id in

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

#{id}

</foreach>

</select>

如果不起别名的话报错如下

更改为array即可

根据传递id的List集合进行查询。

使用list或者collection

测试结果

测试类

测试类

10.2 使用foreach实现批量添加

myqsl数据库中批量添加的方式为

insert into author(author_name,book_name) VALUES('李白','静夜思'),('李白','蜀道难')

接口

int insertManyAuthor( List authors);

配置文件,注意这个没有close和open属性

<insert id="insertManyAuthor">

insert into author(book_name,author_name) value

<foreach collection="collection" item="authors"  separator=",">

(#{authors.bookName},#{authors.authorName})

</foreach>

</insert>

测试类

@Test

public void insertManyAuthor(){

AuthorMapper mapper =session.getMapper(AuthorMapper.class);

ArrayList list =new ArrayList();

list.add(new Author("冰心","寄小读者"));

list.add(new Author("滕王阁序","王勃"));

int i = mapper.insertManyAuthor(list);

session.commit();

if (i>0) {

System.out.println("插入成功");

}else {

System.out.println("插入失败");

}

}

结果

批量添加结果

>>if

10.3 if语句

if语句常用来判断插入的值是否为空

如之前的根据ids来查询结果

根据ids查询结果

But当ids为null时候,就会报错

List list = mapper.getAuthorByIds(null);

Caused by: org.apache.ibatis.builder.BuilderException: The expression 'ids' evaluated to a null value.

之前的sql语句是这样的

<select id="getAuthorByIds" resultMap="MyResultMap">

select* from author where id in

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

#{id}

</foreach>

</select>

修改后的sql语句是这样的

<select id="getAuthorByIds" resultMap="MyResultMap">

select* from author

<if test="ids!=null and ids.length>0">

where id in

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

#{id}

</foreach>

</if>

</select>

当ids为空时候打印的sql是,即查询全部

Preparing: select * from author

>>where

10.4 where语句

where和if是一对好基友,经常在一起搭配使用,例如查询一个id大于4且名字带有“李”的所有的用户。

author表

接口

List getAuthorsBySelect(@Param("id") Integer id,@Param("name") String name);

配置文件中

<select id="getAuthorsBySelect" resultMap="MyResultMap">

select* from author

<where>

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

and id>#{id}

</if>

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

and  author_name like concat('%',#{name},'%')

</if>

</where>

</select>

测试类

@Test

public void testSelect(){

AuthorMapper mapper =session.getMapper(AuthorMapper.class);

List authors = mapper.getAuthorsBySelect(4,"李");

for (Author author : authors) {

System.out.println(author);

}

}

结果

测试结果

当参数为空时候查询所有

借此机会给大家普及一下where里面的And的使用 ,一直匹配,直到遇到第一个条件满足时候将前面的and去掉。

>>set

10.5 set集合

接口

int updateAuthor(Author author);

配置文件

<update id="updateAuthor" parameterType="author">

update author

<set>

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

author_name=#{authorName},

</if>

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

book_name=#{bookName},

</if>

</set>

where id=#{id}

</update>

测试类

@Test

public void testUpdate(){

AuthorMapper mapper =session.getMapper(AuthorMapper.class);

Author author =new Author();

author.setId(9);

author.setBookName("冰心散文");

author.setAuthorName("冰心");

int i = mapper.updateAuthor(author);

session.commit();

if (i>0) {

System.out.println("更新成功");

}else{

System.out.println("更新失败");

}

}

结果

使用set更新后的

借此机会给大家普及一下set里面的逗号用 ,一直匹配,将最后一个符合条件的逗号去掉。

11 主键回填

11.1当id设置成自增长时

当向数据库中插入一个字段时候,将插入的所有信息返回包括id。

将刚刚的配置文件内容更改为

<update id="updateAuthor" parameterType="author" useGeneratedKeys="true" keyProperty="id" keyColumn="id">

update author

<set>

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

author_name=#{authorName},

</if>

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

book_name=#{bookName},

</if>

</set>

where id=#{id}

</update>

测试类中添加一条语句即可

System.out.println("主键回填>>>>>>>>>>"+author);

测试运行结果为

主键回填结果

11.2当id不为自增长且为varchar类型时

创建一个Cat表

CREATE TABLE `cat` (

  `id` varchar(255) DEFAULT NULL,

  `name` varchar(50) DEFAULT NULL

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

创建实体类

public class Cat {

private Stringid;

private Stringname;

}

配置文件中,注意返回值类型是java.lang.String

<insert id="insertCat">

<selectKey keyProperty="id" keyColumn="id" order="BEFORE" resultType="java.lang.String">

select uuid();

</selectKey>

insert into cat set id=#{id},name=#{name}

</insert>


测试类

@Test

public void testCat(){

CatMapper mapper =session.getMapper(CatMapper.class);

Cat cat =new Cat();

cat.setName("小花");

mapper.insertCat(cat);

session.commit();

System.out.println(cat);

}

结果

主键回填测试结果

12 一对一查询

创建员工表和部门表两个,一个员工属于一个部门

部门表

CREATE TABLE `department` (

  `id` int(10) NOT NULL AUTO_INCREMENT,

  `dname` varchar(50) DEFAULT NULL,

  PRIMARY KEY (`id`)

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

员工表,在员工表里面有一个部门表中的id作为字段以此来证明该员工属于那个部门

CREATE TABLE `employee` (

  `id` int(10) NOT NULL AUTO_INCREMENT,

  `name` varchar(50) DEFAULT NULL,

  `sex` varchar(10) DEFAULT NULL,

  `age` int(10) DEFAULT NULL,

  `phone` varchar(50) DEFAULT NULL,

  `address` varchar(50) DEFAULT NULL,

  `did` int(10) DEFAULT NULL,

  PRIMARY KEY (`id`)

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

员工表和部门表之间的关系

员工表和部门表之间的关系

创建部门表实体类

public class Department {

private Integerid;

private Stringname;

}

创建员工表实体类,并且员工表中包含部门类属性

public class Employee {

private Integerid;

private Stringname;

private Stringsex;

private Integerage;

private Stringphone;

private Stringaddress;

private Integerdid;

private Departmentdepartment;

}

部门表中添加内容

部门表

员工表

员工表


接口

List<Employee> getAllEmp();

配置文件

<select id="getAllEmp" resultType="employee">

select e.*,d.* from employee e,department d where e.did=d.id

</select>

测试类

@Test

public void testEmp(){

EmployeeMapper mapper =session.getMapper(EmployeeMapper.class);

List list = mapper.getAllEmp();

for (Employee employee : list) {

System.out.println(employee);

}

}

结果

测试结果

解决办法:自己定义返回类型

配置文件中

<resultMap id="myResultMap" type="com.model.Employee">

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

<result column="name" property="name"></result>

<result column="age" property="age"></result>

<result column="sex" property="sex"></result>

<result column="address" property="address"></result>

<result column="phone" property="phone"></result>

<!--定义一对一映射-->

      <association property="department" javaType="com.model.Department">

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

<result column="depName" property="name"></result>

</association>

</resultMap>

<select id="getAllEmp" resultMap="myResultMap">

select e.*,d.id as depId,d.dname as depName from employee e,department d where e.did=d.id

</select>

配置文件解释

配置文件说明

结果

一对一查询结果

13  一对多

员工和角色是一对多的关系

创建员工表

CREATE TABLE `employee` (

  `id` int(10) NOT NULL AUTO_INCREMENT,

  `name` varchar(50) DEFAULT NULL,

  `sex` varchar(10) DEFAULT NULL,

  `age` int(10) DEFAULT NULL,

  `phone` varchar(50) DEFAULT NULL,

  `address` varchar(50) DEFAULT NULL,

  `did` int(10) DEFAULT NULL,

  PRIMARY KEY (`id`)

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

创建角色表

CREATE TABLE `role` (

  `id` int(10) NOT NULL AUTO_INCREMENT,

  `rname` varchar(50) DEFAULT NULL,

  PRIMARY KEY (`id`)

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

创建员工角色表

CREATE TABLE `e_r` (

  `id` int(10) NOT NULL AUTO_INCREMENT,

  `eid` int(10) DEFAULT NULL,

  `rid` int(10) DEFAULT NULL,

  PRIMARY KEY (`id`)

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

创建部门表

CREATE TABLE `department` (

  `id` int(10) NOT NULL AUTO_INCREMENT,

  `dname` varchar(50) DEFAULT NULL,

  PRIMARY KEY (`id`)

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

员工表中的内容

员工表

角色表中的内容

角色表

员工角色表中的内容

员工角色表

部门表中的内容

部门表

接口

List<Employee> getAllEmpAndRoles();

配置文件

<?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="com.mapper.EmployeeMapper">

<resultMap id="myResultMap" type="com.model.Employee">

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

<result column="name" property="name"></result>

<result column="age" property="age"></result>

<result column="sex" property="sex"></result>

<result column="address" property="address"></result>

<result column="phone" property="phone"></result>


        <association property="department" javaType="com.model.Department">

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

<result column="depName" property="name"></result>

</association>

<!--定义一对一映射 注意是ofType-->

        <collection property="roles" ofType="com.model.Role">

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

<result column="rName" property="name"></result>

</collection>

</resultMap>

<select id="getAllEmp" resultMap="myResultMap">

select e.*,d.id as depId,d.dname as depName from employee e,department d where e.did=d.id

</select>

<select id="getAllEmpAndRoles" resultMap="myResultMap">

select e.*,er.*,r.id as rid,GROUP_CONCAT(r.rname) as rName,d.id as depId,d.dname as depName from employee e,e_r er,department d, role r

where e.did=d.id and er.eid=e.id and er.rid=r.id

GROUP BY e.id

</select>

</mapper>

测试类

@Test

public void testEmp(){

EmployeeMapper mapper =session.getMapper(EmployeeMapper.class);

List list = mapper.getAllEmpAndRoles();

for (Employee employee : list) {

System.out.println(employee);

}

}

结果

查询结果

问题:

如果查询结果是一下这样的,如何将rName合并成上图

更改前的查询结果

使用GROUP_CONCAT(要合并的字段)......   GROUP BY 用户表.id

14 延迟加载

11.1一对迟加载

什么是迟加载?举个栗子来说了吧。

员工表中的属性

public class Employee {

private Integerid;

private Stringname;

private Stringsex;

private Integerage;

private Stringphone;

private Stringaddress;

private Integerdid;

private Department department;

private List<Role> roles;

}

当我只想获取员工表中的基本字段(除了)department和roles

接口中,注意员工接口中声明部门属性。

public interface EmployeeMapper {

List getAllEmp();

List getAllEmp(Integer id);

List getAllEmpAndRoles();

Department getEepById(Integer did);

}

配置文件中

配置文件中

测试类

测试类

结果

结果

添加懒加载

添加懒加载

结果

结果

当想获取Department属性时候在加载

测试类中

获取department

结果

结果

11.2一对多迟加载

接口中

List<Role> getRoles(Integer id);

配置文件中

配置文件中
配置文件中

测试文件中

测试文件

结果

结果

12  缓存


mybatis一级缓存即查询缓存

查询两次只执行一次查询语句

一级缓存用例

一级缓存的作用域是session,session结束后缓存停止。

二级缓存的作用域是sqlSession

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容