Java进阶:Mybatis学习
一、Mybatis快速入门
1.Mybatis简介
1.1原始jdbc操作(查询数据)
1.2原始jdbc操作(插入数据)
1.3 原始jdbc操作的分析
原始jdbc开发存在的问题如下:
- 数据库连接创建、释放频繁造成系统资源浪费从而影响系统性能
- sql 语句在代码中硬编码,造成代码不易维护,实际应用 sql 变化的可能较大,sql 变动需要改变java代码。
- 查询操作时,需要手动将结果集中的数据手动封装到实体中。插入操作时,需要手动将实体的数据设置到sql语句的占位符位置
应对上述问题给出的解决方案:
- 使用数据库连接池初始化连接资源
- 将sql语句抽取到xml配置文件中
- 使用反射、内省等底层技术,自动将实体与表进行属性与字段的自动映射
1.4 什么是Mybatis
- mybatis 是一个优秀的基于java的持久层框架,它内部封装了jdbc,使开发者只需要关注sql语句本身,而不需要花费精力去处理加载驱动、创建连接、创建statement等繁杂的过程。
- mybatis通过xml或注解的方式将要执行的各种 statement配置起来,并通过java对象和statement中sql的动态参数进行映射生成最终执行的sql语句。
- 最后mybatis框架执行sql并将结果映射为java对象并返回。采用ORM思想(Object Relation Mapping对象关系映射)解决了实体和数据库映射的问题,对jdbc 进行了封装,屏蔽了jdbc api 底层访问细节,使我们不用与jdbc api 打交道,就可以完成对数据库的持久化操作。
2.Mybatis的快速入门
2.1 MyBatis开发步骤
MyBatis官网地址:http://www.mybatis.org/mybatis-3/
MyBatis开发步骤:
添加MyBatis的坐标
<dependencies><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.22</version></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.4.6</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version></dependency> </dependencies>
创建user数据表
DROP TABLE IF EXISTS user; CREATE TABLE user(id INT PRIMARY KEY NOT NULL AUTO_INCREMENT,username VARCHAR(255),password VARCHAR(255) )INSERT INTO user (username,password) values ('zhangsan','123'),('lisi','123'),('wangwu','123'),('zhaoliu','123'),('tianqi','123')
编写User实体类
编写映射文件UserMapper.xml(主要写SQL语句)
① 添加约束头<?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">
② 编写SQL
③ 注意:一般映射文件目录与java下的目录相同。
编写核心文件SqlMapConfig.xml(主要进行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">
② 编写核心配置
③ 注意:除了编写配置,还需要加载映射文件。
编写测试类
2.2 环境搭建
导入MyBatis的坐标和其他相关坐标
<!--mybatis坐标--> <dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.4.5</version> </dependency> <!--mysql驱动坐标--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.6</version> <scope>runtime</scope> </dependency> <!--单元测试坐标--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <!--日志坐标--> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.12</version> </dependency>
创建user数据表
编写User实体
package com.itheima.domain;public class User {private int id;private String username;private String password;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}@Overridepublic String toString() {return "User{" +"id=" + id +", username='" + username + '\'' +", password='" + password + '\'' +'}';} }
编写UserMapper映射文件
<?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="userMapper"><select id="findAll" resultType="com.itheima.domain.User">select *from user</select></mapper>
编写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><!--配置数据源环境--><environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="com.mysql.jdbc.Driver"/><property name="url"value="jdbc:mysql://localhost:3306/test?useUnicode=true & characterEncoding=UTF-8 & serverTimezone=Asia/Shanghai"/><property name="username" value="root"/><property name="password" value="131415"/></dataSource></environment></environments><!--加载映射文件--><mappers><mapper resource="com/itheima.mapper/UserMapper.xml"/></mappers> </configuration>
2.3 编写测试代码
package com.itheima.test;import com.itheima.domain.User;
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.Test;import java.io.IOException;
import java.io.InputStream;
import java.util.List;public class MyBatisTest {@Testpublic void test1() throws IOException {//获取核心配置文件InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");// 获得session工厂对象SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);// 获得session会话对象SqlSession sqlSession = sqlSessionFactory.openSession();// 执行操作 参数:namespace + idList<User> userList = sqlSession.selectList("userMapper.findAll");// 打印数据System.out.println(userList);// 释放资源sqlSession.close();}
}
测试结果
2.4 知识小结
MyBatis开发步骤:
①添加MyBatis的坐标
②创建user数据表
③编写User实体类
④编写映射文件UserMapper.xml
⑤编写核心文件SqlMapConfig.xml
⑥编写测试类
3. MyBatis的映射文件概述
4. MyBatis的增删改查操作
4.1 MyBatis的插入数据操作
1)编写UserMapper映射文件
<mapper namespace="userMapper"> <insert id="add" parameterType="com.itheima.domain.User"> insert into user values(#{id},#{username},#{password}) </insert>
</mapper>
2)编写插入实体User的代码
@Test
public voidtest2() throws IOException {// 模拟User对象User user = new User();user.setUsername("tom");user.setPassword("abc");//获取核心配置文件InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");// 获得session工厂对象SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);// 获得session会话对象SqlSession sqlSession = sqlSessionFactory.openSession();// 执行操作 参数:namespace + idsqlSession.insert("userMapper.save", user);// myBatis执行更新操作,提交事务sqlSession.commit();// 释放资源sqlSession.close();
}
3)插入操作注意问题
- 插入语句使用insert标签
- 在映射文件中使用parameterType属性指定要插入的数据类型
- Sql语句中使用#{实体属性名}方式引用实体中的属性值
- 插入操作使用的API是sqlSession.insert(“命名空间.id”,实体对象);
- 插入操作涉及数据库数据变化,所以要使用sqlSession对象显示的提交事务,即sqlSession.commit()
4.2 MyBatis的修改数据操作
1)编写UserMapper映射文件
<mapper namespace="userMapper"><update id="update" parameterType="com.itheima.domain.User">update user set username=#{username},password=#{password} where id=#{id}</update>
</mapper>
2)编写修改实体User的代码
@Test
public void test3() throws IOException {// 模拟User对象User user = new User();user.setId(6);user.setUsername("tom");user.setPassword("123");//获取核心配置文件InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");// 获得session工厂对象SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);// 获得session会话对象SqlSession sqlSession = sqlSessionFactory.openSession();// 执行操作 参数:namespace + idsqlSession.update("userMapper.update", user);// myBatis执行更新操作,提交事务sqlSession.commit();// 释放资源sqlSession.close();
}
3)修改操作注意问题
- 修改语句使用update标签
- 修改操作使用的API是sqlSession.update(“命名空间.id”,实体对象);
4.3 MyBatis的删除数据操作
1)编写UserMapper映射文件
<!--删除操作-->
<delete id="delete" parameterType="java.lang.Integer">deletefrom userwhere id = #{id}
</delete>
2)编写删除数据的代码
@Test
public void test4() throws IOException {//获取核心配置文件InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");// 获得session工厂对象SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);// 获得session会话对象SqlSession sqlSession = sqlSessionFactory.openSession();// 执行操作 参数:namespace + idsqlSession.delete("userMapper.delete", 6);// myBatis执行更新操作,提交事务sqlSession.commit();// 释放资源sqlSession.close();
}
3)删除操作注意问题
- 删除语句使用delete标签
- Sql语句中使用#{任意字符串}方式引用传递的单个参数
- 删除操作使用的API是sqlSession.delete(“命名空间.id”,Object);
4.4 知识小结
增删改查映射配置与API:
查询数据: List<User> userList = sqlSession.selectList("userMapper.findAll");<select id="findAll" resultType="com.itheima.domain.User">select * from User</select>
添加数据: sqlSession.insert("userMapper.add", user);<insert id="add" parameterType="com.itheima.domain.User">insert into user values(#{id},#{username},#{password})</insert>
修改数据: sqlSession.update("userMapper.update", user);<update id="update" parameterType="com.itheima.domain.User">update user set username=#{username},password=#{password} where id=#{id}</update>
删除数据:sqlSession.delete("userMapper.delete",3);<delete id="delete" parameterType="java.lang.Integer">delete from user where id=#{id}</delete>
5. MyBatis核心配置文件概述
5.1 MyBatis核心配置文件层级关系
5.2 MyBatis常用配置解析
environments标签
数据库环境的配置,支持多环境配置
其中,事务管理器(transactionManager)类型有两种:
- JDBC:这个配置就是直接使用了JDBC 的提交和回滚设置,它依赖于从数据源得到的连接来管理事务作用域。
- MANAGED:这个配置几乎没做什么。它从来不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文)。 默认情况下它会关闭连接,然而一些容器并不希望这样,因此需要将 closeConnection 属性设置为 false 来阻止它默认的关闭行为。
其中,数据源(dataSource)类型有三种:
- UNPOOLED:这个数据源的实现只是每次被请求时打开和关闭连接。
- POOLED:这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来。
- JNDI:这个数据源的实现是为了能在如 EJB 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的引用。
mapper标签
该标签的作用是加载映射的,加载方式有如下几种:
① 使用相对于类路径的资源引用,例如:
<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
② 使用完全限定资源定位符(URL),例如:
<mapper url="file:///var/mappers/AuthorMapper.xml"/>
③ 使用映射器接口实现类的完全限定类名,例如:
<mapper class="org.mybatis.builder.AuthorMapper"/>
④ 将包内的映射器接口实现全部注册为映射器,例如:
<package name="org.mybatis.builder"/>
Properties标签
实际开发中,习惯将数据源的配置信息单独抽取成一个properties文件,该标签可以加载额外配置的properties文件
typeAliases标签
类型别名是为Java 类型设置一个短的名字。原来的类型名称配置如下
配置typeAliases,为com.itheima.domain.User定义别名为user
上面我们是自定义的别名,mybatis框架已经为我们设置好的一些常用的类型的别名
5.3 知识小结
核心配置文件常用配置:
properties标签:该标签可以加载外部的properties文件
<properties resource="jdbc.properties"></properties>
typeAliases标签:设置类型别名
<typeAlias type="com.itheima.domain.User" alias="user"></typeAlias>
mappers标签:加载映射配置
<mapper resource="com/itheima/mapper/UserMapping.xml"></mapper>
environments标签:数据源环境配置标签
<!--配置数据源环境-->
<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>
6.MyBatis相应API
6.1 SqlSession工厂构建器SqlSessionFactoryBuilder
常用API:SqlSessionFactory build(InputStream inputStream)
通过加载mybatis的核心文件的输入流的形式构建一个SqlSessionFactory对象
String resource = "org/mybatis/builder/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(inputStream);
其中, Resources 工具类,这个类在 org.apache.ibatis.io 包中。Resources 类帮助你从类路径下、文件系统或一个 web URL 中加载资源文件。
6.2 SqlSession工厂对象SqlSessionFactory
SqlSessionFactory 有多个个方法创建SqlSession 实例。常用的有如下两个:
6.3 SqlSession会话对象
SqlSession 实例在 MyBatis 中是非常强大的一个类。在这里你会看到所有执行语句、提交或回滚事务和获取映射器实例的方法。
执行语句的方法主要有:
<T> T selectOne(String statement, Object parameter)
<E> List<E> selectList(String statement, Object parameter)
int insert(String statement, Object parameter)
int update(String statement, Object parameter)
int delete(String statement, Object parameter)
操作事务的方法主要有:
void commit()
void rollback()
二、Mybatis的Dao层实现
1.Mybatis的Dao层实现
1.1 传统开发方式
1.1.1编写UserDao接口
public interface UserDao {List<User> findAll() throws IOException;
}
1.1.2.编写UserDaoImpl实现
public class UserDaoImpl implements UserDao {public List<User> findAll() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sqlSessionFactory.openSession();List<User> userList = sqlSession.selectList("userMapper.findAll");sqlSession.close();return userList;}
}
1.1.3 测试传统方式
@Test
public void testTraditionDao() throws IOException {UserDao userDao = new UserDaoImpl();List<User> all = userDao.findAll();System.out.println(all);
}
1.2 代理开发方式
1.2.1 代理开发方式介绍
采用 Mybatis 的代理开发方式实现 DAO 层的开发,这种方式是我们后面进入企业的主流。
Mapper 接口开发方法只需要程序员编写Mapper 接口(相当于Dao 接口),由Mybatis 框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。
Mapper 接口开发需要遵循以下规范:
Mapper.xml文件中的namespace与mapper接口的全限定名相同
Mapper接口方法名和Mapper.xml中定义的每个statement的id相同
Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql的parameterType的类型相同
Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同
1.2.2 编写UserMapper接口
1.2.3 测试编写UserMapper接口 与UserMapper.xml
1.2.4 测试代理方式
@Test
public void testProxyDao() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sqlSessionFactory.openSession();//获得MyBatis框架生成的UserMapper接口的实现类UserMapper userMapper = sqlSession.getMapper(UserMapper.class);User user = userMapper.findById(1);System.out.println(user);sqlSession.close();
}
1.3 知识小结
MyBatis的Dao层实现的两种方式:
手动对Dao进行实现:传统开发方式
代理方式对Dao进行实现:
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
2.MyBatis映射文件深入
2.1 动态sql语句
2.1.1 动态sql语句概述
Mybatis 的映射文件中,前面我们的 SQL 都是比较简单的,有些时候业务逻辑复杂时,我们的 SQL是动态变化的,此时在前面的学习中我们的 SQL 就不能满足要求了。
参考的官方文档,描述如下:
2.1.2 动态 SQL 之<if>
我们根据实体类的不同取值,使用不同的 SQL语句来进行查询。比如在 id如果不为空时可以根据id查询,如果username 不同空时还要加入用户名作为条件。这种情况在我们的多条件组合查询中经常会碰到。
一般情况下,我们会加一个where 1 = 1
来进行条件的拼接控制
但是组件中为我们提供了where
标签,可以不使用where 1 = 1
<select id="findByCondition" parameterType="user" resultType="user">select * from User<where><if test="id!=0">and id=#{id}</if><if test="username!=null">and username=#{username}</if></where>
</select>
当查询条件id和username都存在时,控制台打印的sql语句如下:
package com.itheima.text;import com.itheima.domain.User;
import com.itheima.mapper.UserMapper;
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.Test;import java.io.IOException;
import java.io.InputStream;
import java.util.List;public class MapperTest {@Testpublic void test1() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sessionFactory.openSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);// 模拟条件userUser condition = new User();condition.setId(1);condition.setUsername("zhangsan");
// condition.setPassword("123");List<User> userList = mapper.findByCondition(condition);System.out.println(userList);}
}
当查询条件只有id存在时,控制台打印的sql语句如下:
package com.itheima.text;import com.itheima.domain.User;
import com.itheima.mapper.UserMapper;
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.Test;import java.io.IOException;
import java.io.InputStream;
import java.util.List;public class MapperTest {@Testpublic void test1() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sessionFactory.openSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);// 模拟条件userUser condition = new User();condition.setId(1);
// condition.setUsername("zhangsan");
// condition.setPassword("123");List<User> userList = mapper.findByCondition(condition);System.out.println(userList);}
}
2.1.3 动态 SQL 之<foreach>
循环执行sql的拼接操作,例如:SELECT * FROM USER WHERE id IN (1,2,5)。
<select id="findByIds" parameterType="list" resultType="user">select * from User<where><foreach collection="array" open="id in(" close=")" item="id" separator=",">#{id}</foreach></where>
</select>
测试代码片段如下:
… … …//获得MyBatis框架生成的UserMapper接口的实现类
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
int[] ids = new int[]{2,5};
List<User> userList = userMapper.findByIds(ids);
System.out.println(userList);
… … …
查询结果:
foreach标签的属性含义如下:
标签用于遍历集合,它的属性:
- collection:代表要遍历的集合元素,注意编写时不要写#{}
- open:代表语句的开始部分
- close:代表结束部分
- item:代表遍历集合的每个元素,生成的变量名
- sperator:代表分隔符
2.2 SQL片段抽取
Sql 中可将重复的 sql 提取出来,使用时用 include 引用即可,最终达到 sql 重用的目的
<!--抽取sql片段简化编写-->
<sql id="selectUser" select * from User</sql>
<select id="findById" parameterType="int" resultType="user"><include refid="selectUser"></include> where id=#{id}
</select>
<select id="findByIds" parameterType="list" resultType="user"><include refid="selectUser"></include><where><foreach collection="array" open="id in(" close=")" item="id" separator=",">#{id}</foreach></where>
</select>
2.3 知识小结
MyBatis映射文件配置:
<select>
:查询<insert>
:插入<update>
:修改<delete>
:删除<where>
:where条件<if>
:if判断<foreach>
:循环<sql>
:sql片段抽取
3. MyBatis核心配置文件深入
3.1typeHandlers标签
无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时, 都会用类型处理器将获取的值以合适的方式转换成 Java 类型。下表描述了一些默认的类型处理器(截取部分)。
你可以重写类型处理器或创建你自己的类型处理器来处理不支持的或非标准的类型。具体做法为:实现 org.apache.ibatis.type.TypeHandler 接口, 或继承一个很便利的类 org.apache.ibatis.type.BaseTypeHandler, 然后可以选择性地将它映射到一个JDBC类型。例如需求:一个Java中的Date数据类型,我想将之存到数据库的时候存成一个1970年至今的毫秒数,取出来时转换成java的Date,即java的Date与数据库的varchar毫秒值之间转换。
开发步骤:
定义转换类继承类BaseTypeHandler
覆盖4个未实现的方法,其中setNonNullParameter为java程序设置数据到数据库的回调方法,getNullableResult为查询时 mysql的字符串类型转换成 java的Type类型的方法
在MyBatis核心配置文件中进行注册
测试转换是否正确
package com.itheima.test;import com.itheima.domain.User; import com.itheima.mapper.UserMapper; 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.Test;import java.io.IOException; import java.io.InputStream; import java.util.Date;public class MyBatisTest {@Testpublic void test2() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sessionFactory.openSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);User user = mapper.findById(8);System.out.println(user.getBirthday());sqlSession.commit();sqlSession.close();}@Testpublic void test1() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sessionFactory.openSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);// 创建userUser user = new User();user.setUsername("ceshi");user.setPassword("asd");user.setBirthday(new Date());// 执行保存mapper.save(user);sqlSession.commit();sqlSession.close();} }
<!--注册类型处理器--> <typeHandlers><typeHandler handler="com.itheima.handle.DateTypeHandle"/> </typeHandlers>
测试添加操作:
user.setBirthday(new Date()); userMapper.add2(user);
数据库数据:
测试查询操作:
3.2 plugins标签
MyBatis可以使用第三方的插件来对功能进行扩展,分页助手PageHelper是将分页的复杂操作进行封装,使用简单的方式即可获得分页的相关数据
开发步骤:
① 导入通用PageHelper的坐标
② 在mybatis核心配置文件中配置PageHelper插件
③ 测试分页数据获取
①导入通用PageHelper坐标
<!-- 分页助手 -->
<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>
②在mybatis核心配置文件中配置PageHelper插件
<!-- 注意:分页助手的插件 配置在通用馆mapper之前 -->
<plugin interceptor="com.github.pagehelper.PageHelper"><!-- 指定方言 --><property name="dialect" value="mysql"/>
</plugin>
③测试分页代码实现
@Test
public void testPageHelper(){//设置分页参数PageHelper.startPage(1,2);List<User> select = userMapper2.select(null);for(User user : select){System.out.println(user);}
}
获得分页相关的其他参数
//其他分页的数据
PageInfo<User> pageInfo = new PageInfo<User>(select);
System.out.println("总条数:"+pageInfo.getTotal());
System.out.println("总页数:"+pageInfo.getPages());
System.out.println("当前页:"+pageInfo.getPageNum());
System.out.println("每页显示长度:"+pageInfo.getPageSize());
System.out.println("是否第一页:"+pageInfo.isIsFirstPage());
System.out.println("是否最后一页:"+pageInfo.isIsLastPage());
3.3 知识小结
MyBatis核心配置文件常用标签:
- properties标签:该标签可以加载外部的properties文件
- typeAliases标签:设置类型别名
- environments标签:数据源环境配置标签
- typeHandlers标签:配置自定义类型处理器
- plugins标签:配置MyBatis的插件
三、Mybatis多表查询
1.Mybatis多表查询
1.1 一对一查询
1.1.1 一对一查询的模型MapperScannerConfigurer
用户表和订单表的关系为,一个用户有多个订单,一个订单只从属于一个用户
一对一查询的需求:查询一个订单,与此同时查询出该订单所属的用户
DROP TABLE IF EXISTS orders;CREATE TABLE orders(id INT PRIMARY KEY NOT NULL AUTO_INCREMENT,ordertime VARCHAR(255),total DOUBLE,uid INT
)
1.1.2一对一查询的语句
对应的sql语句:
select * from orders o,user u where o.uid=u.id;
查询的结果如下:
1.1.3 创建Order和User实体
public class Order {private int id;private Date ordertime;private double total;//代表当前订单从属于哪一个客户private User user;
}public class User {private int id;private String username;private String password;private Date birthday;}
1.1.4 创建OrderMapper接口
public interface OrderMapper {List<Order> findAll();
}
1.1.5 配置OrderMapper.xml
<mapper namespace="com.itheima.mapper.OrderMapper"><resultMap id="orderMap" type="com.itheima.domain.Order"><result column="uid" property="user.id"></result><result column="username" property="user.username"></result><result column="password" property="user.password"></result><result column="birthday" property="user.birthday"></result></resultMap><select id="findAll" resultMap="orderMap">select * from orders o,user u where o.uid=u.id</select>
</mapper>
其中<resultMap>
还可以配置如下:通过association标签进行实体属性类型配置
<resultMap id="orderMap" type="com.itheima.domain.Order"><result property="id" column="id"></result><result property="ordertime" column="ordertime"></result><result property="total" column="total"></result><association property="user" javaType="com.itheima.domain.User"><result column="uid" property="id"></result><result column="username" property="username"></result><result column="password" property="password"></result><result column="birthday" property="birthday"></result></association>
</resultMap>
1.1.6 测试结果
@Test
public void test1() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sessionFactory.openSession();OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);List<Order> orders = mapper.findAll();for (Order order : orders) {System.out.println(order);}sqlSession.close();
}
1.2 一对多查询
1.2.1 一对多查询的模型
用户表和订单表的关系为,一个用户有多个订单,一个订单只从属于一个用户
一对多查询的需求:查询一个用户,与此同时查询出该用户具有的订单
1.2.2 一对多查询的语句
对应的sql语句:
select *,o.id oid from user u left join orders o on u.id=o.uid;
查询的结果如下:
1.2.3 修改User实体
public class Order {private int id;private Date ordertime;private double total;//代表当前订单从属于哪一个客户private User user;
}public class User {private int id;private String username;private String password;private Date birthday;//代表当前用户具备哪些订单private List<Order> orderList;
}
1.2.4 创建UserMapper接口
public interface UserMapper {List<User> findAll();
}
1.2.5 配置UserMapper.xml
<mapper namespace="com.itheima.mapper.UserMapper"><resultMap id="userMap" type="user"><id column="uid" property="id"/><result column="username" property="username"/><result column="password" property="password"/><result column="birthday" property="birthday"/><!--配置集合信息property:集合名称ofType:当前集合中的数据类型--><collection property="orderList" ofType="order"><!--封装order的数据--><id column="oid" property="id"/><result column="ordertime" property="ordertime"/><result column="total" property="total"/></collection></resultMap><select id="findAll" resultMap="userMap">SELECT *FROM USER u,orders oWHERE u.id = o.uid</select>
</mapper>
1.2.6 测试结果
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> all = mapper.findAll();
for(User user : all){System.out.println(user.getUsername());List<Order> orderList = user.getOrderList();for(Order order : orderList){System.out.println(order);}System.out.println("----------------------------------");
}
1.3 多对多查询
1.3.1 多对多查询的模型
用户表和角色表的关系为,一个用户有多个角色,一个角色被多个用户使用
多对多查询的需求:查询用户同时查询出该用户的所有角色
1.3.2 多对多查询的语句
对应的sql语句:select u.,r.,r.id rid from user u left join user_role ur on u.id=ur.user_id
inner join role r on ur.role_id=r.id;
查询的结果如下:
1.3.3 创建Role实体,修改User实体
public class User {private int id;private String username;private String password;private Date birthday;//代表当前用户具备哪些订单private List<Order> orderList;//代表当前用户具备哪些角色private List<Role> roleList;
}public class Role {private int id;private String rolename;}
1.3.4 添加UserMapper接口方法
List<User> findAllUserAndRole();
1.3.5 配置UserMapper.xml
<resultMap id="userRoleMap" type="com.itheima.domain.User"><result column="id" property="id"></result><result column="username" property="username"></result><result column="password" property="password"></result><result column="birthday" property="birthday"></result><collection property="roleList" ofType="com.itheima.domain.Role"><result column="rid" property="id"></result><result column="rolename" property="rolename"></result></collection>
</resultMap>
<select id="findAllUserAndRole" resultMap="userRoleMap">select u.*,r.*,r.id rid from user u left join user_role ur on u.id=ur.user_idinner join role r on ur.role_id=r.id
</select>
1.3.6 测试结果
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> all = mapper.findAllUserAndRole();
for(User user : all){System.out.println(user.getUsername());List<Role> roleList = user.getRoleList();for(Role role : roleList){System.out.println(role);}System.out.println("----------------------------------");
}
1.4 知识小结
**MyBatis多表配置方式:
**
- 一对一配置:使用
<resultMap>
+<association>
做配置** - 一对多配置:使用
<resultMap>
+<collection>
做配置** - 多对多配置:使用
<resultMap>
+<collection>
做配置**
四、Mybatis的注解开发
1 MyBatis的常用注解
这几年来注解开发越来越流行,Mybatis也可以使用注解开发方式,这样我们就可以减少编写Mapper
映射文件了。我们先围绕一些基本的CRUD来学习,再学习复杂映射多表操作。
- @Insert:实现新增
- @Update:实现更新
- @Delete:实现删除
- @Select:实现查询
- @Result:实现结果集封装
- @Results:可以与@Result 一起使用,封装多个结果集
- @One:实现一对一结果集封装
- @Many:实现一对多结果集封装
1.1 MyBatis的增删改查
我们完成简单的user表的增删改查的操作
private UserMapper userMapper;@Before
public void before() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sqlSessionFactory.openSession(true);userMapper = sqlSession.getMapper(UserMapper.class);
}@Test
public void testAdd() {User user = new User();user.setUsername("测试数据");user.setPassword("123");user.setBirthday(new Date());userMapper.add(user);
}
@Test
public void testUpdate() throws IOException {User user = new User();user.setId(16);user.setUsername("测试数据修改");user.setPassword("abc");user.setBirthday(new Date());userMapper.update(user);
}@Test
public void testDelete() throws IOException {userMapper.delete(16);
}
@Test
public void testFindById() throws IOException {User user = userMapper.findById(1);System.out.println(user);
}
@Test
public void testFindAll() throws IOException {List<User> all = userMapper.findAll();for(User user : all){System.out.println(user);}
}
修改MyBatis的核心配置文件,我们使用了注解替代的映射文件,所以我们只需要加载使用了注解的Mapper接口即可
<mappers><!--扫描使用注解的类--><mapper class="com.itheima.mapper.UserMapper"></mapper>
</mappers>
或者指定扫描包含映射关系的接口所在的包也可以
<mappers><!--扫描使用注解的类所在的包--><package name="com.itheima.mapper"></package>
</mappers>
1.2 MyBatis的注解实现复杂映射开发
实现复杂关系映射之前我们可以在映射文件中通过配置来实现,使用注解开发后,我们可以使用@Results注解,@Result注解,@One注解,@Many注解组合完成复杂关系的配置
1.3 一对一查询
1.3.1 一对一查询的模型
用户表和订单表的关系为,一个用户有多个订单,一个订单只从属于一个用户
一对一查询的需求:查询一个订单,与此同时查询出该订单所属的用户
1.3.2 一对一查询的语句
对应的sql语句:
select * from orders;select * from user where id=查询出订单的uid;
查询的结果如下:
1.3.3 创建Order和User实体
public class Order {private int id;private Date ordertime;private double total;//代表当前订单从属于哪一个客户private User user;
}public class User {private int id;private String username;private String password;private Date birthday;}
1.3.4 创建OrderMapper接口
public interface OrderMapper {List<Order> findAll();
}
1.3.5 使用注解配置Mapper
方式一
@Select("select *,o.id oid from orders o,user u where o.uid=u.id") @Results({@Result(column = "oid",property = "id"),@Result(column = "ordertime",property = "ordertime"),@Result(column = "total",property = "total"),@Result(column = "uid",property = "user.id"),@Result(column = "username",property = "user.username"),@Result(column = "password",property = "user.password") }) public List<Order> findAll();
方式二
@Select("select * from orders") @Results({@Result(column = "id", property = "id"),@Result(column = "ordertime", property = "ordertime"),@Result(column = "total", property = "total"),@Result(property = "user", //要封装的属性名称column = "uid", //根据哪个字段去查询user表的数据javaType = User.class, //要封装的实体类型//select属性 代表查询那个接口的方法获得数据one = @One(select = "com.itheima.mapper.UserMapper.findById")) }) public List<Order> findAll();
public interface UserMapper {@Select("select * from user where id=#{id}")User findById(int id);}
1.3.6 测试结果
@Test
public void testSelectOrderAndUser() {List<Order> all = orderMapper.findAll();for(Order order : all){System.out.println(order);}
}
1.4 一对多查询
1.4.1 一对多查询的模型
用户表和订单表的关系为,一个用户有多个订单,一个订单只从属于一个用户
一对多查询的需求:查询一个用户,与此同时查询出该用户具有的订单
1.4.2 一对多查询的语句
对应的sql语句:
select * from user;select * from orders where uid=查询出用户的id;
查询的结果如下:
1.4.3 修改User实体
public class Order {private int id;private Date ordertime;private double total;//代表当前订单从属于哪一个客户private User user;
}public class User {private int id;private String username;private String password;private Date birthday;//代表当前用户具备哪些订单private List<Order> orderList;
}
1.4.4 创建UserMapper接口
List<User> findAllUserAndOrder();
1.4.5 使用注解配置Mapper
public interface UserMapper {@Select("select * from user")@Results({@Result(id=true ,column = "id",property = "id"),@Result(column = "username",property = "username"),@Result(column = "password",property = "password"),@Result(property = "orderList",column = "id",javaType = List.class,many = @Many(select = "com.itheima.mapper.OrderMapper.findByUid"))})public List<User> findUserAndOrderAll();
}public interface OrderMapper {@Select("select * from orders where uid=#{uid}")List<Order> findByUid(int uid);}
1.4.6 测试结果
List<User> all = userMapper.findAllUserAndOrder();
for(User user : all){System.out.println(user.getUsername());List<Order> orderList = user.getOrderList();for(Order order : orderList){System.out.println(order);}System.out.println("-----------------------------");
}
1.5 多对多查询
1.5.1 多对多查询的模型
用户表和角色表的关系为,一个用户有多个角色,一个角色被多个用户使用
多对多查询的需求:查询用户同时查询出该用户的所有角色
1.5.2 多对多查询的语句
对应的sql语句:
select * from user;select * from role r,user_role ur where r.id=ur.role_id and ur.user_id=用户的id
查询的结果如下:
1.5.3 创建Role实体,修改User实体
public class User {private int id;private String username;private String password;private Date birthday;//代表当前用户具备哪些订单private List<Order> orderList;//代表当前用户具备哪些角色private List<Role> roleList;
}public class Role {private int id;private String rolename;}
1.5.4 添加UserMapper接口方法
List<User> findAllUserAndRole();
1.5.5 使用注解配置Mapper
public interface UserMapper {@Select("select * from user")@Results({@Result(id = true,property = "id",column = "id"),@Result(property = "username",column = "username"),@Result(property = "password",column = "password"),@Result(property = "birthday",column = "birthday"),@Result(property = "roleList",column = "id",javaType = List.class,many = @Many(select = "com.itheima.mapper.RoleMapper.findByUid"))
})
List<User> findAllUserAndRole();}public interface RoleMapper {@Select("select * from role r,user_role ur where r.id=ur.role_id and ur.user_id=#{uid}")List<Role> findByUid(int uid);
}
1.5.6 测试结果
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> all = mapper.findAllUserAndRole();
for(User user : all){System.out.println(user.getUsername());List<Role> roleList = user.getRoleList();for(Role role : roleList){System.out.println(role);}System.out.println("----------------------------------");
}
多对多主要体现在调用的接口是查询了两张数据表,也就是多对多关系必须有一张中间表
Java进阶:Mybatis学习相关推荐
- JAVA进阶知识学习-day10
一.缓冲流 1.1 缓冲流,也叫高效流,是对4个基本的流的增强,按照数据类型分类: 字节缓冲流: BufferedInputStream,BufferedOutputStream 字符缓冲流: B ...
- 美团149道面试题,全会拿40Koffer没问题(Java程序员学习方向)
一.数据结构与算法基础 · 说一下几种常见的排序算法和分别的复杂度. · 用Java写一个冒泡排序算法 · 描述一下链式存储结构. · 如何遍历一棵二叉树? · 倒排一个LinkedList. · 用 ...
- Java进阶篇设计模式之十三——观察者模式和空对象模式
简介 观察者模式又叫发布-订阅(Publish/Subscribe)模式.模型-视图(Model/View)模式.源-监听器(Source/Listener)模式或从属者(Dependents)模式. ...
- Java框架学习笔记--Mybatis学习
一.Mybatis学习 1.Mybatis简介 简介:Mybatis开源免费框架.原名叫iBatis,2010在googlecode,2013年迁移到github2 作用:数据访问层框架.底层是对JD ...
- ssm毕设项目基于的少儿编程学习系统2lsiy(java+VUE+Mybatis+Maven+Mysql+sprnig)
ssm毕设项目基于的少儿编程学习系统2lsiy(java+VUE+Mybatis+Maven+Mysql+sprnig) 项目运行 环境配置: Jdk1.8 + Tomcat8.5 + Mysql + ...
- java毕业设计高校学习社区mybatis+源码+调试部署+系统+数据库+lw
java毕业设计高校学习社区mybatis+源码+调试部署+系统+数据库+lw java毕业设计高校学习社区mybatis+源码+调试部署+系统+数据库+lw 本源码技术栈: 项目架构:B/S架构 开 ...
- Java进阶学习-7 面向对象程序设计原则
title: Java进阶学习-7 面向对象程序设计原则 date: 2020-02-02 18:02:27 tags: 以一个城堡游戏为例子谈面向对象程序设计原则 Game.java package ...
- ssm毕设项目益学-校园学习互助y0ig7(java+VUE+Mybatis+Maven+Mysql+sprnig)
ssm毕设项目益学-校园学习互助y0ig7(java+VUE+Mybatis+Maven+Mysql+sprnig) 项目运行 环境配置: Jdk1.8 + Tomcat8.5 + Mysql + H ...
- springboot项目:老年教育学习系统fte91(java+VUE+Mybatis+Maven+Mysql)
springboot项目:老年教育学习系统fte91(java+VUE+Mybatis+Maven+Mysql) 一.项目运行 环境配置: Jdk1.8 + Tomcat8.5 + Mysql + H ...
- java毕业设计大学生学习交友平台Mybatis+系统+数据库+调试部署
java毕业设计大学生学习交友平台Mybatis+系统+数据库+调试部署 java毕业设计大学生学习交友平台Mybatis+系统+数据库+调试部署 本源码技术栈: 项目架构:B/S架构 开发语言:Ja ...
最新文章
- C++条件编译:#ifdef
- Windows10 对系统盘C 有效清理
- 常见java考试题与面试题一
- mysql format不要逗号,mysql格式化小数
- php如何修改xml中element值,php修改xml节点的值
- MySQL(10)--- 创建数据表
- mysql调换数据_mysql互换表中两列数据方法
- 解决JSP路径问题的方法(jsp文件开头path, basePath作用)
- JSK-24 函数规律【基础】
- 原生JavaScript实现幻灯片效果
- scara机器人动荷载_【机器人在线】SCARA机械结构参数计算说明 下
- 【破解APP抓包限制】Xposed+JustTrustMe关闭SSL证书验证!
- NVIDIA GeForce Experience 无法登录解决办法
- CleanMyMac X4.12.2免费版MAC电脑系统磁盘优化工具
- C语言show用法,show的用法及句型
- Java 获取月初时间
- 讯飞AIUI ubuntu linux使用
- After Effects Duik: Rigging Animation Tools After Effects 的绑定与动画工具 Duik插件 Lynda课程中文字幕
- 【学习方法】关于记忆方法的思考,如何快速、短时、高效地记忆内容?
- 七种影视截图截屏小方法