1. 入门案例

新建一个maven项目

  1. 选择:maven-archetype-quickstart

一、环境搭建

1、依赖

  1. <dependency>
  2. <groupId>org.mybatis</groupId>
  3. <artifactId>mybatis</artifactId>
  4. <version>3.5.4</version>
  5. </dependency>

2、创建实体类

  1. 实体类属性和表中的字段一致
  2. 实现Serializable接口【序列化接口】
  3. 该重写的方法都重写了

3、创建该类的接口,定义抽象方法

  1. // 接口 操作User表
  2. public interface UserDao {
  3. // 返回List集合 集合中保存的是User对象
  4. List<User> getUser();
  5. }

4、创建主配置文件

在resources目录下创建 mybatis-config.xml文件

官网: https://mybatis.org/mybatis-3/zh/getting-started.html

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE configuration
  3. PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-config.dtd">
  5. <configuration>
  6. <environments default="development">
  7. <environment id="development">
  8. <transactionManager type="JDBC"/>
  9. <dataSource type="POOLED">
  10. <property name="driver" value="${driver}"/>
  11. <property name="url" value="${url}"/>
  12. <property name="username" value="${username}"/>
  13. <property name="password" value="${password}"/>
  14. </dataSource>
  15. </environment>
  16. </environments>
  17. <mappers>
  18. <mapper resource="org/mybatis/example/BlogMapper.xml"/>
  19. </mappers>
  20. </configuration>

5、创建映射配置文件UserMapper.xml

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <mapper namespace="org.mybatis.example.BlogMapper">
  6. <select id="selectBlog" resultType="Blog">
  7. select * from Blog where id = #{id}
  8. </select>
  9. </mapper>

6、测试

1.mybatis增删改查 - 图2

二、环境搭建的注意事项

  1. 在MyBatis中他把持久层的操作接口名称和映射文件也叫做:Mapper

  2. 所以UserDao.java 这个接口和UserMapper.xml是一致的

  3. 在IDEA创建目录的时候,他和包是不一样的

  • 包:com.yixuexi.dao 三层结构
  • 目录:com/yixuexi/dao 一层目录 【所以要分三次创建】

4. MyBatis的映射配置文件 必须和dao结构的包结构相同

  • 也就是说在resources文件夹下建出和dao同样的结构目录然后mapper放进去

  • 为什么在resources里面搞Mapper?

  • 因为 main—>java 目录下的xml文件不会被编译

  • 在一定要用/

  • 在一定要用/

5. 映射文件的Mapper标签的namespace属性的取值必须是dao接口的全限定类名

6. 映射配置文件的操作配置,id属性的取值必须是dao接口的方法名

  • 当遵从了第以上的要求之后,在开发中就不需要再去写dao的实现类

7. 映射配置文件的resultType=”com.yixuexi.entity.User“ 是说 查询出来的结果封装到这个实体类中

全类名

三、入门案例

1、使用xml的方式

当配置好了mybatis的主配置文件和 Mapper之后 就可以进行编写java代码了

1、读取配置文件

不建议使用绝对路径和相对路径

建议使用(有bug为解决)

  • 类加载器读取
  1. String path = Thread.currentThread().getContextClassLoader().getResource("mybatis-config.xml").getPath();
  • ServletContext对象的getRealPath()方法

2、创建SqlSessionFactory工厂

  • mybatis使用了构建者模式[设计模式]

  • builer就是构建者,调用builer的builer()方法传进去一个流 即可

  • 把对象的创建细节隐藏,使用者直接调用方法即可拿到对象

3、创建SqlSession

  • 生产SqlSession使用了工厂模式[解耦合]

4、创建Dao接口的代理对象

创建DAO接口实现类 使用了代理模式[不修改源码的基础上对已有的方法增强]

5、执行dao中的方法

6、释放资源

1.mybatis增删改查 - 图3

2、注意事项

  • 千万不要忘记在Mapper.xml 也就是映射文件中要告诉要封装到那个实体类中
  1. <select id="getUser" resultType="com.yixuexi.entity.User">

四、使用注解的方式

  • 使用注解的话 主配置文件还是要有的 mybatis-config.xml 不能动

  • 但是Mapper.xml文件就可以不创建了

  • 比xml文件更加的便捷

在接口中的方法上面使用@Select(“select * from user”)

  1. public interface UserDao {
  2. @Select("select * from user")
  3. List<User> getUsers();
  4. }

然后在主配置文件中注册上

  1. <mapper class="com.yixuexi.dao.UserDao"></mapper>

要求使用全限定类型(代包名)【把那个接口的全名写到 class属性中】

1.mybatis增删改查 - 图4

2. 增删改

一、增

在环境搭建好的基础上

1、在dao接口中创建一个抽象方法

  1. public interface UserDao {
  2. int saveUser(User user);
  3. }

2、在映射配置文件中

  1. <!--namespace 写dao接口的全名 代包名-->
  2. <mapper namespace="com.yixuexi.dao.UserDao">
  3. <!--id 写dao接口中的方法名字 不带()-->
  4. <!--parameterType 写对应那个实体类 从那个实体类中取数据 输入参数类型-->
  5. <insert id="saveUser" parameterType="com.yixuexi.entity.User">
  6. <!--取数据用 #{属性名或者getId() 都可以}-->
  7. insert into user(id,name,password) values(#{id},#{name},#{password})
  8. </insert>
  9. </mapper>

3、在执行的时候一定不要忘记sqlSession.commit()

因为自动提交事务是关闭的

二、保存操作的细节,获取保存数据的id

  1. Select last_insert_id(); 会查询到最后一次保存的id

1.mybatis增删改查 - 图5

1、在dao接口中创建一个方法

  1. //保存一个User 并且返回该User的id
  2. Integer saveUserReturnId(User user);

2、在映射文件中这样写

  1. <!--id写到接口中方法名 parameterType输入参数类型-->
  2. <!--useGeneratedKeys:设置是否使用JDBC的getGenereatedKeys方法获取主键并赋值到keyProperty设置的领域模型属性中-->
  3. <insert id="saveUserReturnId" keyProperty="id" useGeneratedKeys="true" parameterType="com.yixuexi.entity.User">
  4. insert into user(name,password) values(#{name},#{password})
  5. </insert>

3、然后再注册该mapper,

(已经注册过的不需要在注册)

4、在测试类写的注意事项

  • 返回的值并不是id属性

  • 要想得到id属性从user对象中getId即可

  • 一定不要忘记 session.commit();

  • id必须为主键并且自增长 auto_increment

1.mybatis增删改查 - 图6

三、改

在环境搭建好的基础上

1、在UserDao接口上新建一个方法

  1. public interface UserDao {
  2. //用户更改的方法
  3. void updateUser(User user);
  4. }

2、在映射配置文件中写sql

  1. <update id="updateUser" parameterType="com.yixuexi.entity.User">
  2. update user set name = #{name},password = #{password} where id = #{id}
  3. </update>

3、在主配置文件中注册上

  1. <mappers>
  2. <mapper resource="com/yixuexi/dao/UserDaoMapper.xml"></mapper>
  3. </mappers>

4、在测试文件中写测试方法

注意最后一定要SqlSession.commit(); // 提交

四、删除

在环境搭建好的基础上

1、给UserDao接口上新建一个方法

  1. public interface UserDao {
  2. void deleteUser(Integer id);
  3. }

2、在映射配置文件中写sql

  1. 类型不是User而是Integer
  2. <update id="deleteUser" parameterType="java.lang.Integer">
  3. 取值直接用#{}
  4. delete from user where id = #{id}
  5. </update>

3、在主配置文件中注册

  1. <mappers>
  2. <mapper resource="com/yixuexi/dao/UserDaoMapper.xml"></mapper>
  3. </mappers>

4、在测试文件中写测试方法

注意最后一定要SqlSession.commit();

3. 查询

一、根据Id查询用户

1、在dao接口中

  1. public interface UserDao {
  2. //查询一个的方法,根据id查询
  3. User findOne(Integer id);
  4. }

2、在映射配置文件中

  1. <mapper namespace="com.yixuexi.dao.UserDao">
  2. <!--
  3. resultType写最后封装到哪里,
  4. parameterType 写值是什么类型
  5. -->
  6. <select id="findOne" resultType="com.yixuexi.entity.User" parameterType="java.lang.Integer">
  7. select * from user where id = #{id}
  8. </select>
  9. </mapper>

3、在主配置文件中注册

  1. <mapper resource="com/yixuexi/dao/UserDaoMapper.xml"></mapper>

测试

二、Like查询

1、在接口中定义一个抽象方法

  1. //模糊查询like [通过名字查询]
  2. List<User> findLike(String name);

2、在映射文件中写sql

  1. <select id="findLike" resultType="com.yixuexi.entity.User" parameterType="String">
  2. select * from user where name like #{name}
  3. Select * from user where name like '%${value}%';
  4. 也可以这样,不过这个value是固定的,% 是占位符【不常用】
  5. 测试类中调用 方法的时候就不需要再提供 % 占位符了
  6. </select>

3、在主配置文件中配置

(如果配置了就不需要再配置了)

4、Test类

  1. 注意事项:再测试传值的时候 一定要带上占位符,因为在映射配置文件中不能写 % _
  2. List<User> like = mapper.findLike("%曹%");

三、详解Like 查询中 #{} 和 ‘${value}’的差距

  • #{}在传参的时候需要字符串添加 占位符 % _

  • 使用的是预编译的数据库操作对象,更加安全 不会有 SQL注入

  • PrepatedStatement

  • 常用,但是不能用作排序查询

  • ![](https://g.yuque.com/gr/latex?%7Bvalue%7D%20%E5%8F%AF%E4%BB%A5%E7%9B%B4%E6%8E%A5%E5%9C%A8%E6%98%A0%E5%B0%84%E6%96%87%E4%BB%B6%E4%B8%AD%E5%86%99%E5%8D%A0%E4%BD%8D%E7%AC%A6%20#card=math&code=%7Bvalue%7D%2A%2A%20%2A%2A%E5%8F%AF%E4%BB%A5%E7%9B%B4%E6%8E%A5%E5%9C%A8%E6%98%A0%E5%B0%84%E6%96%87%E4%BB%B6%E4%B8%AD%E5%86%99%E5%8D%A0%E4%BD%8D%E7%AC%A6%2A%2A%20%2A%2A){%vlaue%}

  • 使用的是 普通的数据库操作对象 可能会产生 SQL 注入问题

  • Statement

  • 一般可以使用在 排序查询的时候,传进去 ${value} desc / asc

  • 不管传进来的是什么 都是 ${value}

  1. select * from user order by id ${value}

四、查询总用户 (一行一列型)

1、在dao接口中添加方法

  1. //测试查询总记录条数
  2. Integer countAll();

2、在映射配置文件中配置

  1. 只需要配置一个 结果界类型 resultType即可
  2. <select id="countAll" resultType="Integer">
  3. select count(*) from user
  4. </select>

3、在主配置文件中注册

如果该映射文件被注册了则不用进行注册

4、测试方法

4. 输入类型/resultMap/Properties/typeAliases

一、parameterType (输入类型)

1、传递简单的类型

int Integer String 都可以

2、pojo对象(实体类对象)

MyBatis使用ognl表达式解析对象字段的值,

Ognl:对象导航图语言

通过对象的取值方法来获取数据,在写法上把get省略了

例如:

  • 类中的写法:user.getUsername();
  • ognl表达式:user.username;

MyBatis为什么能直接写username,而不用user呢

因为在parameterType中已经提供了属性所属的类,此时不需要写对象名

传递pojo包装对象

  • 有一个QueryVo类 里面有一个属性是 private User user 【提供了get set方法】
  • 当查询时,在parameter=”com.yixuexi.entity.QueryVo” 那么下面的sql语句如何调用到 user对象的username
  1. Select * ``from`` user where name = #{user.username}

直接点即可 因为ognl表达式,parameter已经提供了QueryVo

有多个对象组合在一起 完成查询

二、resultMap(结果类型)

(映射文件中的配置)

1、解决实体类属性和列名不一致的两种解决方案

1)第一种(执行效率快,开发效率低)

  1. 类中的属性为 userId,username,userPassword

  2. 为了能让数据库查询出来的数据 封装到User对象中去,可以采用起别名的方式

  3. 在映射xml文件中这样写sql

  1. <select id="findAll" resultType="com.yixuexi.entity.User" parameterType="String">
  2. Select id as userId,name as username,password as userPassword from user;
  3. </select>

2)第二种 (执行效率低,开发效率变快)

  1. 采用MyBatis提供的一个配置
  2. 直接在dao映射文件中配置
  1. <!--id 就是起个名,在使用的时候用这个名就行 type 是哪个实体类-->
  2. <resultMap id="userMap" type="com.yixuexi.entity.User">
  3. <!--配置主键字段的对应 property 写类中的属性名 column写数据库中对应的字段名-->
  4. <id property="userId" column="id"></id>
  5. <!--非主键字段的对应-->
  6. <result property="username" column="name"></result>
  7. <result property="userPassword" column="password"></result>
  8. </resultMap>
  1. 如果要使用resultMap对应的话,那么resultType则需要换成resultMap 值就是id
  1. <select id="find" resultMap="userMap">
  2. select * from user;
  3. </select>

三、Properties

1、在主配置文件中 mybatis-config.xml中配置

  1. <configuration>
  2. <!-- 定义变量 -->
  3. <properties>
  4. <property name="driver" value="com.mysql.jdbc.Driver"/>
  5. <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
  6. <property name="username" value="root"/>
  7. <property name="password" value="0000"/>
  8. </properties>
  9. <environments default="development">
  10. <environment id="development">
  11. <transactionManager type="JDBC"/>
  12. <dataSource type="POOLED">
  13. <!-- 使用变量 -->
  14. <property name="driver" value="${driver}"/>
  15. <property name="url" value="${url}"/>
  16. <property name="username" value="${username}"/>
  17. <property name="password" value="${password}"/>
  18. </dataSource>
  19. </environment>
  20. </environments>
  21. <mappers>
  22. <mapper resource="com/yixuexi/dao/UserDaoMapper.xml"></mapper>
  23. </mappers>
  24. </configuration>

2、引用外部文件配置

  • (可以在标签内部配置连接数据库的信息,也可以通过属性引用外部配置文件配置信息)

  • resources属性: 常用于指定配置文件的位置,是按照类路径的写法,并且必须存储在类路径下

  • 要用到properties标签中的**resources**属性 [在类的根路径下 src下]

  1. <properties resource="mybatis.properties">
  2. </properties>
  • Mybatis.properties中这样写
  1. driver=com.mysql.jdbc.Driver
  2. url=jdbc:mysql://localhost:3306/mybatis
  3. username=root
  4. password=0000
  • 注意事项:
  1. properties`中的信息`key`必须和 `dataSource`里面的的`value`中的`${一致}

四、typeAliases

  • (主配置文件中的标签)
  • 使用typeAliases配置别名,他只能配置 实体类 中类得别名,

1、typeAlias

  1. <typeAliases>
  2. <!--type:实体类的具体全限定类名 alias:别名-->
  3. <typeAlias type="com.yixuexi.domain.User" alias="user"></typeAlias>
  4. </typeAliases>

用了此标签后,resultTypeparameterType不能在用全限定名字了,要使用alias别名

2、Package常用

  1. <typeAliases>
  2. <!--直接配置一个包,包下的所有类都会配置-->
  3. <!--用于指定要配置的别名的包,当指定之后,该包下的实体类都会注册别名,并且类名就是别名-->
  4. <package name="com.yixuexi.domain"/>
  5. </typeAliases>

mapers标签下的package子标签(映射配置文件中的)

  1. <mappers>
  2. <!--
  3. 1. 使用package的要求
  4. - mapper文件必须和dao接口名必须完全相同,包括大小写
  5. - mapper文件和dao文件必须在同一目录【mapper文件在resources目录下也行 前提是也有 com.xxx.xxx】
  6. 2. package标签用于指定dao接口所在的包,当指定了之后就不需要在写mapper了 resouces和class也不用了-->
  7. <package name="com.yixuexi.dao"/>
  8. </mappers>
  9. <!--不用插件也行,要符合上面的要求-->
  10. <-- pom文件插件 -->
  11. <!--配置资源插件,在java目录下的xml文件也会被编译到,放到最后那里就行-->
  12. <resources>
  13. <resource>
  14. <directory>src/main/java</directory>
  15. <includes>
  16. <include>**/*.properties</include>
  17. <include>**/*.xml</include>
  18. </includes>
  19. <filtering>false</filtering>
  20. </resource>
  21. </resources>

五、MyBatis连接池

我们在实际开发中都会使用连接池

减少获取连接时所消耗的时间

mybatis提供了3中方式的配置

配置的位置

主配置文件 mybatis-config.xml中的dataSource标签的type属性

Type属性的取值:

  • POOLED(默认) :采用传统的javax.sql.DataSource规范中的连接池 mybatis中有针对它的实现、

  • UNPOOLED:传统的获取连接的方式,虽然也实现了javax.sql.DataSource接口,但是名没有使用池的思想

  • JNDI:采用服务器提供的JNDI技术实现,来获取DataSource对象,不同的服务器之间不同

注意:如果是不web获取maven的war功能,是不能使用的

1、UNPOOLED和POOLED差别

1)UNPOOLED

通过源码可以看到 UNPOOLED是每次使用的执行sql的时候都会在底层进行一套JDBC操作

注册驱动,获取连接……

2)POOLED

使用的是池的思想

5. 事务/动态sql/多表查询

一、MyBatis事务(spring时再讲)

在创建sqlsession对象时传一个参数进去 true时 得到的SqlSession的事务自动提交时开启的

  1. SqlSession sqlSession = ``**build.openSession(**``**true**``**);** ``(开发时用的少)

二、动态sql

动态SQL 官网

1、 标签

在映射配置文件中这样写

  1. <select id="findUserByCondition" resultType="com.yixuexi.entity.User" parameterType="com.yixuexi.entity.User">
  2. select * from user where 1 = 1 // 使用if标签 where 1=1不能省略
  3. <if test="name != null">
  4. and name = #{name}
  5. </if>
  6. </select>
  • 这里面的if 并且的关系是and 或者的关系是or

  • 其实就是sql语句的拼接 在select语句后面 加个if就是拼接上if里面的内容

  • 如果有多个条件 可以添加多个if

  1. select * from user where 1 = 1
  2. <if test="name != null">
  3. and name = #{name}
  4. </if>
  5. <if test="password != null">
  6. and password = #{password}
  7. </if>

多个if都会执行

2、where标签

  • 使用where标签可以省略 where 1 = 1
  • 就是在 if标签外面套一层 where包裹起来
  1. <select id="findUserByCondition" resultType="com.yixuexi.entity.User" parameterType="com.yixuexi.entity.User">
  2. select * from user
  3. <where>
  4. <if test="name != null">
  5. and name = #{name}
  6. </if>
  7. <if test="password != null">
  8. and password = #{password}
  9. </if>
  10. </where>
  11. </select>

3、foreach标签

  1. <select id="findUserByIds" parameterType="com.yixuexi.entity.QueryVoIds" resultType="com.yixuexi.entity.User">
  2. select * from user
  3. <where> <!--添加了where之后 就不用再手写 where 1=1 -->
  4. <!--如果这个对象里面的list集合不是null,并且 list集合的个数大于0个 则遍历 -->
  5. <if test="list != null and list.size > 0">
  6. <!--
  7. - collection:遍历哪个集合,集合名称
  8. - open:开头添加什么 添加 and id in(
  9. } open哪里加and是因为 where标签会帮你加 where 1=1 不加and不行
  10. - close:在结尾添加什么 添加 )
  11. - item:(起个名)把遍历出来的每一项添加到 open和close之间,用,进行分割
  12. - separator:用什么进行分割
  13. - #{id}:item起的什么名字 这里就用什么名字
  14. -->
  15. <foreach collection="list" open="and id in(" close=")" item="id" separator=",">
  16. #{id}
  17. </foreach>
  18. </if>
  19. </where>
  20. </select>

三、多表查询

1、一对一的数据库查询

1、创建Account子类的方式 (不常用)

SQL语句是这样的 (一个用户对一个账户)

  1. SELECT
  2. a.* , u.name AS NAME ,u.password AS PASSWORD
  3. FROM
  4. account a
  5. JOIN
  6. USER u
  7. ON
  8. a.uid = u.id
  • 此时mybatis需要准备好两张表 一张Account表 和 一张继承Account的表 继承的表里面有需要查出来的别的字段

  • AccountUser子表 需要重写toString() 并且重写时,调用父类的toString() super.toString()

  • 然后在AccountDao接口中创建一个方法

  • List``**<AccountUser**``> findAllAccountUser();

  • 返回值需是Account的子类,因为子类中有父类没有的属性 name 和 password

  • 然后在映射文件中写sql语句

  1. <select id="findAllAccountUser" resultType="AccountUser">
  2. <!--因为这里再主配置文件中配置了typeAliases所以直接写类名即可-->
  3. select
  4. a.* , u.name ,u.password
  5. from
  6. account a
  7. join
  8. user u
  9. on
  10. a.uid = u.id
  11. </select>
  • 这里的数据库列名需要和实体类中的属性名一致,所以再创建子类的时候 属性名要写好

2、从表中有实体引用(常用)

1) 从表实体类中应该含一个主表实体的包对象引用

  1. public class Account {
  2. private Integer id;
  3. private Integer uid;
  4. private Double money;
  5. //从表实体类中应该有一个主表的对象
  6. private User user;
  7. }

student学生表 引用了外键 class的id 班级表 那么说 student就是从表 class就是主表

2) SQL语句

  1. select
  2. a.*,u.id,u.name,u.password
  3. from
  4. account a
  5. join
  6. user u
  7. on
  8. a.uid = u.id

3) 因为Account(子表)表中有一个主表的对象,那么再查询结果封装的时候是 没办法把User封装进去的,需要这样设置

  1. <!--定义一个能封装account和user的resultMap-->
  2. <resultMap id="accountUserMap" type="Account">
  3. <!--定义主键字段-->
  4. <id property="id" column="id"></id>
  5. <!--定义非主键字段-->
  6. <result property="uid" column="uid"></result>
  7. <result property="money" column="money"></result>
  8. <!--一对一的关系映射:配置user的内容-->
  9. <!--property:该实体类中的哪个对应关系的主表属性-->
  10. <!--column:通过哪一个 字段进行获取的-->
  11. <!--javaType:最后的结果封装到哪个类 正常写法是com.xxx.xx 用了TypeAlia..所以直接类名-->
  12. <association property="user" column="uid" javaType="User">
  13. <!--在里面写User的属性和数据库对应起来-->
  14. <id property="id" column="id"></id>
  15. <result property="name" column="name"></result>
  16. <result property="password" column="password"></result>
  17. </association>
  18. </resultMap>

4) sql语句原封不动的写就行

<select id="findAll" resultMap="**accountUserMap**">这里写上resultMap起的id名


2、一对多(一个用户有多个账户)

  • 账户表的外键引用了用户表的主键,那么说账户表是从表,用户表示主表
  • 一对多关系映射:主表实体中应该包含从表实体的集合引用

1、UserDao接口中的方法

  1. List<User> findAll();

2、User实体类中的属性

  1. public class User {
  2. private Integer id;
  3. private String name;
  4. private String password;
  5. //一对多关系映射:主表实体中应该包含从表实体的集合引用
  6. private List<Account> accounts;
  7. }

3、SQL语句

  1. select
  2. u.*,a.id as aid ,a.uid,a.money
  3. from
  4. user u
  5. left join
  6. account a
  7. on
  8. u.id = a.uid
  9. 因为有两个id所以给account表中的id起一个别名

4、在映射配置文件中写对应关系

  1. <!--定义User的resultMap 一对多查询-->
  2. <!--id 随便起一个名字 type:类型仍然是一个User 配置了别名所以直接写类名-->
  3. <resultMap id="UserAccountMap" type="User">
  4. <id property="id" column="id"></id>
  5. <result property="name" column="name"></result>
  6. <result property="password" column="password"></result>
  7. <!--配置user对象中accounts集合的映射-->
  8. <!--property:User对象的Account属性名-->
  9. <!--ofType:集合中元素的类型(用了别名 不然要写权限定类名)-->
  10. <!--一对多需要用 collection标签 -->
  11. <collection property="accounts" ofType="Account">
  12. <id property="id" column="aid"></id>
  13. <result property="uid" column="uid"></result>
  14. <result property="money" column="money"></result>
  15. </collection>
  16. </resultMap>

1.mybatis增删改查 - 图7

  • 为什么是column是aid 因为查询的有两个id 一个用户id 一个 账户id 为了区分在起了个别名
  • 同时 sql语句也要写上 a.id as aid

5、编写测试类

3、多对多

多对多,三张表,关系表两个外键

示例:用户和角色

  • 一个用户有多个角色
  • 一个角色可以赋予多个用户

各自包含对方一个集合引用

  • 当我们查询用户是,可以同时得到用户所包含的角色信息
  • 当我们查询角色是,可以同时得到角色的所赋予的用户信息

1、SQL语句

  1. 查询身份并且显示对应的用户信息
  2. SELECT
  3. u.*,r.id AS role_id,r.role_name,r.role_desc
  4. FROM
  5. USER u
  6. JOIN
  7. user_role ur #连接关系表 条件是用户表的id等于关系表的uid
  8. ON
  9. u.id = ur.uid
  10. JOIN
  11. role r ##连接身份表 条件是身份表的id等于关系表的rid
  12. ON
  13. r.id = ur.rid
  14. 数据库里面的id会有重复 所以要起一个别名,不过不要忘了配置文件的cloumn属性也改成别名

2、在RoleDao中创建一个方法

  1. public interface RoleDao {
  2. /**
  3. * 查询所有角色
  4. * @return
  5. */
  6. List<Role> findAll();
  7. }

3、Role实体类中的属性是这样的

  1. public class Role implements Serializable {
  2. private Integer roleId;
  3. private String roleName;
  4. private String roleDesc;
  5. //多对多的关系映射,一个角色可以赋予多个用户
  6. private List<User> users;
  7. }

4、在RoleDaoMapper.xml文件中配置一下对应关系

  1. <!--id就是起个名字 type:是什么类型,(全限定类名,但是又typeAlia)-->
  2. <resultMap id="roleUserMap" type="Role">
  3. <!--配置主键 properties:类中的属性 column:数据库中的字段-->
  4. <id property="roleId" column="role_id"></id>
  5. <result property="roleName" column="role_name"></result>
  6. <result property="roleDesc" column="role_desc"></result>
  7. <!--配置role对象中的users集合映射关系-->
  8. <!--properties:写要配置哪个属性名-->
  9. <!--ofType:集合里面是什么数据类型(全限定类名 …)-->
  10. <collection property="users" ofType="User" >
  11. <id property="id" column="id"></id>
  12. <result property="name" column="name"></result>
  13. <result property="password" column="password"></result>
  14. </collection>
  15. </resultMap>

5、编写测试类

  1. RoleDao mapper = session.getMapper(RoleDao.class);
  2. List<Role> all = mapper.findAll();
  3. for (Role role : all) {
  4. System.out.print(role);
  5. System.out.println(role.getUsers());
  6. }
  • 在循环的时候调用一下role.getUsers();
  • 或者直接把users重写进toString() // 这样会直接输出 list集合的toString() 而哪个List集合的toString()已经重写