MyBatis
1.概述
MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁
移到了google code,并且改名为MyBatis 2013年 11 月迁移到Github。
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了
几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置
和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记
录。
复习JDBC
//1.注册驱动
Class.forname("com.mysql.jdbc.Driver");
//2.获取连接
Connection connection =Drivermannager.getConnection(url,username,password);
//3.定义sql
String sql ="select * from student where id=?";
//4.预编译
PreparedStatement statement =connnection.preparedStatement(sql);
//5.设置参数
statement.setInteger(1,2001);
//6.执行sql,封装结果
ResultSet result = statement.excuteQuery();
虽然传统JDBC也可以解决我们操作数据库的需求,但是它的功能简单并且耦合度高,如果我们在
项目上线后修改某条sql语句,就需要去修改Java源码,并对项目进行重新的打包部署等一系列工作,操
作起来相当的繁琐。
这里我们还需要介绍一个大名鼎鼎的全自动映射ORM框架: Hibernate
Hibernate框架:全自动映射ORM框架,但不支持sql,需要额外学习hql,增加了开发成本
ORM: Object Relation Mapping 对象关系映射,简单说就是把数据库表和实体类的属性对应起
来,让我们可以操作实体类就可以实现操作数据库表。
(Hibernate框架)
该框架的设计旨在消除SQL:即便是你没学过SQL,也可以使用该框架,它将JDBC的操作进行了封
装,你只需要去调用它相应的功能即可。但是这些功能不支持自定义SQL,即后期无法对SQL进行优
化,你只能用框架自己生成的SQL进行数据库操作。虽然它的HQL支持自定义SQL,但是你需要去花时
间学习,这无疑也增加了开发的时间和成本。
MyBatis框架优化了Hibernate框架的的缺点:MyBatis虽然对JDBC的操作也进行了封装,但是它
把编写SQL的部分还是交给了程序员来完成,这样就不会失去SQL的灵活性。
2.为什么使用MyBatis
JDBC
- SQL编写在代码中,耦合度比较高
- 实际开发中SQL会经常被更新,维护不易
Hibernate和JPA
- 内部自动生成SQL,不方便特殊优化
- 长难复杂的SQL,对Hibernate来说处理很不容易
- 基于全映射的全自动框架,进行字段部分映射比较困难,并且会导致数据库性能下降。
JPA是Java Persistence API的简称,中文名Java持久层API,是JDK 5.0注解或XML描述对象-关系
表的映射关系,并将运行期的实体对象持久化到数据库中
MyBatis
-
SQL和Java编码分离,功能划分清楚,一个专注数据,一个专注业务
-
核心SQL可以自己编写,优化比较方便
3.MyBatis入门
3.1环境搭建
步骤
1.创建Maven工程,并导入相关依赖
2.依照数据库建立对应的实现类
3.创建dao层接口:UserDao
4.创建MyBatis主配置文件:SqlMapConfig.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>
<!-- 配置环境 -->
<environments default="mysql">
<!--配置Mysql环境-->
<environment id="mysql">
<!--配置事务的类型-->
<transactionManager type="JDBC"></transactionManager>
<!--配置数据源(连接池)-->
<dataSource type="POOLED">
<!--配置连接数据库的4个基本信息-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!--指定映射配置文件的位置,映射配置文件指的是每个dao独立的配置文件-->
<mappers>
<mapper resource="com/wdzl/dao/UserDao.xml"/>
</mappers>
</configuration>
5.去Resource
下创建映射配置文件:UserDao.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.wdzl.dao.UserDao"><!--对应dao层接口的全限定类名-->
<select id="findAll" resultType="com.wdzl.pojo.Student"> <!--id属性对应方法的名称,不能随便写-->
select * from student;
</select>
</mapper>
该xml的注意事项
- namespace是对应的全限定类名
- select标签的id属性对应相应的方法名,不能随便写
6.把log4j.properties拷贝到resource目录下
注意事项
1.创建directory 和 package的区别
directory:com.wdzl.dao
创建的是一级目录
package:com.wdzl.dao
创建了三级目录
2.Mybatis的映射配置文件所在目录层级要与对应的dao层接口目录层级相同
3.映射配置文件 mapper标签和namespace属性的值必须对应接口的全限定类名
4.映射配置文件select标签id属性必须与对应接口中的方法名一致,不能随便写。
5.
3.2 测试案例
步骤
1.读取配置文件
2.创建SqlSessionFactry对象—>通过SqlSessionFactoryBuilder对象获取
3.使用工厂对象生产SqlSession对象
4.使用SqlSession对象获取接口的代理对象‘’
5.使用代理对象调用方法
6.释放资源
public class UserDaoTest {
@Test
public void findAllTest() throws IOException {
//1.读取配置文件
InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.创建SqlSessionFactory工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(is);
//3.用工厂生产SqlSession对象
SqlSession session = factory.openSession();
//4.使用SqlSession对象创建dao层的代理对象
UserDao userDao = session.getMapper(UserDao.class);
//5.使用代理对象执行方法
List<Student> students = userDao.findAll();
//遍历
for (Student student : students) {
System.out.println(student);
}
//6. 释放资源
session.close();
is.close();
}
}
3.3.MyBatis注解入门
1.我们新建一个MavenModule“HelloMyBatis_anno”,将上一个Module的内容都复制到该Module中
2.因为该案例使用的是注解方式,所以映射配置文件就不需要了我们可以把它删掉,并在相应的接口方法上写上注解即可
UserDao.java
public interface UserDao {
/**
* 查询所有用户信息
*/
@Select("select * from student")
List<Student> findAll();
}
4.自定义myBatis
4.1.分析
Mybatis在使用代理的方式实现增删改查都做了什么事?
- 创建代理对象
- 在代理对象中创建方法
根据上图分析(对),我们如果想让代码完整执行下来我们需要提供两组信息:
- 连接信息
- 映射信息
- 执行的sql语句
- 封装结果的实体类全限定类名
随着项目功能的扩充,映射信息也会越来越多,所以我们需要使用对象来存储映射信息,那么怎么区分不同的映射信息呢,根据配置文件,我们知道,namespace + id 可以区分映射信息,所以我们可以考虑使用Map集合来存储这部分信息。
分析到这里,整个流程基本就完成了,还有一个难点就是如何使用动态代理创建代理对象和对接口中方法的实现。接下来我们再通过图解的方式给大家分析一下。
4.2.自定义MyBatis
首先我们在第一个项目中,查看以下几个名称对应的是接口还是类
Resource
:类
SqlSession
:接口
SqlSessionFactory
:接口
SqlSessionFactoryBuilder
:类
1.新建Module
- groupId:com.wdzl
- artifactId:与Module名一致
2.我们将第一个入门案例整体拷贝到创建的Module中,并在pom.xml中剔除MyBatis的依赖信息。
此时test测试案例中MyBatis相应的类或接口都会报红,接下来就是一一编写这些类或接口
(自定义MyBatis参照目录)
3.Recources类
先创建相应目录mybatis.io
package com.wdzl.io;
import java.io.InputStream;
/**
* 使用类加载器读取配置文件
* @author lp
* @version 1.0
*/
public class Resources {
/**
* 根据文件路径,获取输入流
* @param filePath
* @return
*/
public static InputStream getResourceAsStream(String filePath) {
return Resources.class.getClassLoader().getResourceAsStream(filePath);
}
}
4.创建SqlSessionFactoryBuilder类
先在 mybatis
包中创建 sqlsession
包
package com.wdzl.SqlSession;
import java.io.InputStream;
/**
* 用于创建SqlSessionFactory工厂对象
* @author lp
* @version 1.0
*/
public class SqlSessionFactoryBuilder {
/**
* 获取SqlSessionFactory工厂对象
* @param inputStream
* @return
*/
public SqlSessionFactory build(InputStream inputStream) {
return all
}
}
因为 build()
方法的返回值类型 SqlSessionFactory
并不存在,此时它是报红的,缺什么我们就创建什么,接下来我们创建 SqlSessionFactory
接口
5.创建 SqlSessionFactory
接口
在 sqlsession
包中创建该接口,通过 SqlSessionFactory
可以获取 SqlSession
对象,所以要在接口中定义对应的方法。
package com.wdzl.SqlSession;
public interface SqlSessionFactory {
SqlSession openSession();
}
6.创建SqlSession
接口
package com.wdzl.SqlSession;
/**
* 自定义MyBatis框架中的核心接口
* 它可以创建dao接口的动态代理对象
*/
public interface SqlSession {
/**
* 根据接口创建代理对象
*
* @param daoInterfaceClass
* @param <T>
* @return
*/
<T> T getMapper(Class<T> daoInterfaceClass);
/**
* 释放资源
*/
void close();
}
此时,我们测试案例中所有爆红的地方都全部修复了
7.在POM中导入XML解析工具类:XMLConfigBuilder 和相关依赖
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>1.1.6</version>
</dependency>
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
导入之后我们来处理报红的问题
- Configuration: 我们通过工具类注释我们知道它是用来存放连接配置信息的类,所以我们创建一个
Configuration
类,并根据下面报红信息确定它的属性有:driver , url , username , password
8.创建Configuration类 ,并添加getter、setter方法
package com.wdzl.pojo;
import java.util.HashMap;
import java.util.Map;
/**
* @author lp
* @version 1.0
*/
public class Configuration {
private String driver;
private String url;
private String username;
private String password;
private Map<String, Mapper> mappers = new HashMap<>();
9.创建Mapper对象
通过上面图解,我们知道Mapper对象的组成 sql语句 和 实体类的全限定类名。所以我们在 domain
包下创建该类
package com.wdzl.pojo;
/**
* 用于封装执行的sql语句和结果类型的全限定类名的类
* @author lp
* @version 1.0
*/
public class Mapper {
private String queryString;//sql语句
private String resultType;//实体类的全限定类名
public String getQueryString() {
return queryString;
}
public void setQueryString(String queryString) {
this.queryString = queryString;
}
public String getResultType() {
return resultType;
}
public void setResultType(String resultType) {
this.resultType = resultType;
}
}
在工具类中导入Mapper后,寻找下图中红框的位置,因为我们现在不涉及注解方式,所以我们直
接将注解相关的内容全部注释,不用去考虑它,只专心的关注XML方式
10.在 Configuration 中添加成员变量: Mappers
11.回到 SqlSessionFactoryBuilder 编写 build
12.新建 SqlSessionFactoryImpl 实现类,实现 SqlSessionFactory 接口。
因为 SqlSession
可以为我们创建代理对象,实现方法,具体这个方法要做什么,是不是封装在
Configration
中,所以我们还需要继续将cfg对象传递给 SqlSession
对象
13.创建 SqlSession 的实现类对象: SqlSessionImpl
package com.wdzl.mybatis.sqlSession;
import com.wdzl.domain.Configuration;
/**
* @author lp
* @version 1.0
*/
public class SqlSessionImpl implements SqlSession {
private Configuration cfg;
public SqlSessionImpl(Configuration cfg) {
this.cfg = cfg;
}
/**
* 创建代理对象
* @param daoInterfaceClass UserDao接口的Class对象
* @param <T>
* @return
*/
@Override
public <T> T getMapper(Class<T> daoInterfaceClass) {
return null;
}
- 使用动态代理实现getMapper()方法。
学过反射,我们知道,对于代理类的方法如何实现,重点就是在这个 InvocationHandler
接口中的 invoke() 方法如何实现。接下来我们就来实现这个接口
15.创建InvocationHandler接口的实现类:MapperProxy
package com.wdzl.mybatis.sqlSession.proxy;
import com.wdzl.domain.Mapper;
import com.wdzl.utils.Executor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Map;
/**
* @author lp
* @version 1.0
*/
public class MapperProxy implements InvocationHandler {
private Map<String, Mapper> mappers;//该变量中包含了sql语句,结果封装的对象等信息。
public MapperProxy(Map<String, Mapper> mappers) {
this.mappers = mappers;
}
/**
* 用于增强方法:findAll()方法
* @param proxy
* @param method
导入工具类后,我们发现selectList()中有两个参数,一个是Mapper对象,另一个是连接对象,因为
连接对象需要cfg,所以我们去SqlSessionImpl中添加一个连接对象的成员变量
* @param args
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws
Throwable {
//1.获取方法名
String methodName = method.getName();
//2.获取方法所在类的名称:全限定类名
String className = method.getDeclaringClass().getTypeName();
//3.图中的key
String key = className+ "." +methodName;
//4. 获取 mappers中的Mapper对象
Mapper mapper = mappers.get(key);
//5. 判断mapper对象是否存在
if (mapper == null) {
throw new IllegalArgumentException("传入的参数有误");
}
//6. 调用工具类执行查询
return new Executor().selectList();//需要导入提前编写好的工具类
}
}
导入工具类后,我们发现selectList()
中有两个参数,一个是Mapper
对象,另一个是连接对象,因为连接对象需要cfg
,所以我们去SqlSessionImpl
中添加一个连接对象的成员变量
16.编写DataSourceUtil
package com.wdzl.utils;
import com.wdzl.pojo.Configuration;
import java.sql.Connection;
import java.sql.DriverManager;
/**
* @author lp
* @version 1.0
* 用于创建数据源的工具类
*/
public class DataSourceUtil {
/**
* 用于获取一个连接
* @param cfg
* @return
*/
public static Connection getConnection(Configuration cfg){
try {
Class.forName(cfg.getDriver());
return DriverManager.getConnection(cfg.getUrl(), cfg.getUsername(), cfg.getPassword());
}catch(Exception e){
throw new RuntimeException(e);
}
}
}
5.使用Mybatis对数据库进行增删改查CRUD(XML方法)
pom依赖文件(记得刷新)
<?xml version="1.0" encoding="UTF-8"?>
<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>
<groupId>com.wdzl</groupId>
<artifactId>mybatis_crud</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!--测试单元-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!--Mysql连接驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<!--日志解析lo4j-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
</project>
1.在UserDao里面创建每个需求的接口方法
public interface UserDao {
/**
* 查询所有用户信息
*/
List<User> findAll();
/**
* 添加用户的方法
* @param user
*/
void addUser(User user);
/**
* 修改用户信息
*/
void updateUser(User user);
/**
* 删除用户
*/
void deleteUser(User user);
/**
* 根据id查询指定用户信息
*/
User findUserById(int id);
/**
* 模糊查询-根据用户名模糊查询用户信息
*/
List<User> findUserByName(String name);
/**
* 查询用户总记录数
*/
int findTotal();
/**
* 根据QueryVo查询用户信息
*/
List<User> findUserByVo(QueryVo vo);
}
2.创建User实体类,与数据库表一一对应,然后添加setter\getter方法、有参无参构造、tostring方法
public class User {
private int uid;
private String username;
private String sex;
private String birthday;
private String address;
3.在xml配置文件中使用mapper
标签及select
标签写上具体的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">
<mapper namespace="com.wdzl.dao.UserDao"><!--对应dao层接口的全限定类名-->
<resultMap id="userMap" type="com.wdzl.pojo.User">
<id property="uid" column="id"></id>
<!--实体类对应--> <!--数据库对应-->
<result property="username" column="username"></result>
</resultMap>
<!--查询所有用户信息的方法-->
<select id="findAll" resultMap="userMap">
select * from user
</select>
<!--添加用户-->
<insert id="addUser" parameterType="com.wdzl.pojo.User">
<selectKey keyProperty="id" order="AFTER" resultType="int">
select last_insert_id();
</selectKey>
insert into user(username,birthday,sex,address) values (#{username},#{birthday},#{sex},#{address})
</insert>
<!--修改信息-->
<update id="updateUser" parameterType="com.wdzl.pojo.User">
update user set address=${address} where username=${username}
</update>
<!--删除用户-->
<delete id="deleteUser" parameterType="com.wdzl.pojo.User">
delete from user where username=#{username}
</delete>
<!--根据id查询用户信息-->
<select id="findUserById" parameterType="java.lang.Integer" resultType="com.wdzl.pojo.User">
select * from user where id=#{id}
</select>
<!--模糊查询-->
<select id="findUserByName" parameterType="string" resultType="com.wdzl.pojo.User">
select * from user where username like #{name}
</select>
<!--查询用户总记录数-->
<select id="findTotal" resultType="int">
select count(id) from user
</select>
<!--根据包装类模糊查询用户数据-->
<select id="findUserByVo" parameterType="com.wdzl.pojo.QueryVo" resultType="com.wdzl.pojo.User">
select * from user where username like #{user.username}
</select>
</mapper>
4.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>
<!-- 配置环境 -->
<environments default="mysql">
<environment id="mysql">
<!--配置事务的类型-->
<transactionManager type="JDBC"></transactionManager>
<!--配置数据源-->
<dataSource type="POOLED">
<!--配置连接数据库的4个基本信息-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/wdzl/dao/UserDao.xml"/>
</mappers>
</configuration>
5.test文件
/**
* UserDao测试类
* @author lp
* @version 1.0
* MyBatis入门案例测试实现步骤
* 1. 读取配置文件
* 2.创建SqlSessionFactory工厂
* 3.用工厂生产SqlSession对象
* 4.使用SqlSession对象创建dao层的代理对象
* 5.使用代理对象执行方法
* 6.释放资源
*/
public class UserDaoTest {
InputStream is;
SqlSessionFactoryBuilder builder;
SqlSessionFactory factory;
SqlSession sqlSession;
UserDao userDao;
@Before
public void init() throws IOException {
//1.读取配置文件
is = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.创建SqlSessionFactory工厂
builder = new SqlSessionFactoryBuilder();
factory = builder.build(is);
//3.用工厂生产SqlSession对象
sqlSession = factory.openSession();
//4.使用SqlSession对象创建dao层的代理对象
userDao = sqlSession.getMapper(UserDao.class);
}
@After
public void destroy() throws IOException {
sqlSession.close();
is.close();
}
@Test
public void findAllTest() throws IOException {
//5.使用代理对象执行方法
List<User> users = userDao.findAll();
//遍历
for (User user :users) {
System.out.println(user);
}
}
@Test
public void testAddUser() throws IOException {
User user = new User(0, "赵童", "男", "2000-01-01", "宝鸡");
// 5.使用代理对象执行方法
userDao.addUser(user);
System.out.println(user);
//提交事务
sqlSession.commit();
System.out.println("--------------------------");
System.out.println(user);
}
@Test
public void testUpdateUser() {
User user = new User();
user.setUsername("赵童");
user.setAddress("西安");
userDao.updateUser(user);
//5.使用代理对象执行方法
List<User> users = userDao.findAll();
//遍历
for (User user2 :users) {
System.out.println(user2);
}
}
@Test
public void testDeleteUser() {
User user = new User();
user.setUsername("赵童");
userDao.deleteUser(user);
//5.使用代理对象执行方法
List<User> users = userDao.findAll();
//遍历
for (User user2 :users) {
System.out.println(user2);
}
}
@Test
public void testFindUserById() {
User user = userDao.findUserById(9);
System.out.println(user);
}
@Test
public void testFindUserByName() {
List<User> users = userDao.findUserByName("%德%");
for (User user :users) {
System.out.println(user);
}
}
@Test
public void testFindTotal() {
int total = userDao.findTotal();
System.out.println(total);
}
@Test
public void testFindByVo() {
QueryVo queryVo = new QueryVo();
User user = new User();
user.setUsername("%德%");
queryVo.setUser(user);
List<User> users = userDao.findUserByVo(queryVo);
for (User user2 : users) {
System.out.println(user2);
}
}
}
6.MyBatis多表查询
在MySql中,表与表之间有三种
一对一 一对多(多对一) 多对多
举例:
一对一 :公民和身份证号:一个公民只能有一个身份证号
一对多、多对一:学生和班级
多对多:学生和老师
特殊:如果将订单取出,这个订单只能属于一个用户,所以,在MyBatis中,就把多对一的关系按照一对一的情况进行处理
6.1.MyBatis中的多表查询
6.1.1-一对一
假设一个账户对应一个用户,一个用户也对应一个账户
需求:查询所有账户信息的同时,显示账户所属用户的信息(一对一)
- 确定SQL语句
SELECT a.id,a.money,u.id,u.username,u.sex,u.address FROM account a,USER u WHERE u.id= a.uid;
- 在实体类中体现一对一的关系
1.添加pom依赖
<?xml version="1.0" encoding="UTF-8"?>
<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>
<groupId>com.wdzl</groupId>
<artifactId>mybatis_manyToOne</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<dependencies>
<!--测试单元-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!--Mysql连接驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<!--日志解析lo4j-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
</project>
2.创建两个实体类,与SQL表的变量一致,然后setter、getter,有参无参,tostring
/**
* 账户表对应实体类
* @author lp
* @version 1.0
*/
public class Account {
private int aid;
private int uid;
private double money;
/**
* 用户表对应实体类
* @author lp
* @version 1.0
*/
public class User {
private int uid;
private String username;
private Date birthday;
private char sex;
private String address;
3.创建接口
/**
* 操作账户表的接口
* @author lp
* @version 1.0
*/
public interface AccountDao {
/**
* 查询账户列表
* @return
*/
List<Account> findAll();
}
/**
* 操作用户表的接口
* @author lp
* @version 1.0
*/
public interface UserDao {
/**
* 查询用户列表
* @return
*/
List<User> findAll();
}
4.创建接口对应的xml的配置文件
- AccountDao.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.wdzl.dao.AccountDao">
<!--定义封装account 和 user 的 resultMap-->
<resultMap id="accountUserMap" type="account">
<id property="aid" column="aid"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
<!--配置一对一的关系映射:配置user的内容-->
<association property="user" javaType="com.wdzl.pojo.User" column="uid">
<id property="uid" column="uid"></id>
<result property="username" column="username"></result>
<result property="birthday" column="birthday"></result>
<result property="sex" column="sex"></result>
<result property="address" column="address"></result>
</association>
</resultMap>
<!--查询账户列表-->
<select id="findAll" resultMap="accountUserMap">
SELECT a.aid,a.money,u.uid,u.username,u.sex,u.address FROM account a , USER u WHERE u.uid = a.uid;
</select>
</mapper>
- UserDao.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.wdzl.dao.AccountDao">
<!--定义封装account 和 user 的 resultMap-->
<resultMap id="accountUserMap" type="account">
<id property="aid" column="aid"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
<!--配置一对一的关系映射:配置user的内容-->
<association property="user" javaType="com.wdzl.pojo.User" column="uid">
<id property="uid" column="uid"></id>
<result property="username" column="username"></result>
<result property="birthday" column="birthday"></result>
<result property="sex" column="sex"></result>
<result property="address" column="address"></result>
</association>
</resultMap>
<!--查询账户列表-->
<select id="findAll" resultMap="accountUserMap">
SELECT a.aid,a.money,u.uid,u.username,u.sex,u.address FROM account a , USER u WHERE u.uid = a.uid;
</select>
</mapper>
5.创建总配置文件
<?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"/>
<!-- <properties url="file:///D:/jdbc.properties"></properties>-->
<!--配置别名-->
<typeAliases>
<!-- <typeAlias type="com.wdzl.pojo.User" alias="aa" ></typeAlias>-->
<package name="com.wdzl.pojo"/>
</typeAliases>
<!-- 配置环境 -->
<environments default="mysql">
<environment id="mysql">
<!--配置事务的类型-->
<transactionManager type="JDBC"></transactionManager>
<!--配置数据源-->
<dataSource type="POOLED">
<!--配置连接数据库的4个基本信息-->
<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="com/wdzl/dao/UserDao.xml"/>
<mapper resource="com/wdzl/dao/AccountDao.xml"/>
</mappers>
</configuration>
此处将数据库连接信息给提取了出来,文件名为jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis2?useUnicode=true&characterEncoding=utf-8
jdbc.username=root
jdbc.password=root
6.Test文件
- AccountTest
/**
* 用户表的测试
*
* @author lp
* @version 1.0
*/
public class AccountTest {
InputStream is;
SqlSessionFactory factory;
SqlSession sqlSession;
AccountDao accountDao;
/**
* 初始化
* @throws IOException
*/
@Before
public void init() throws IOException {
//1.读取配置文件
is = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.获取SqlSession工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
factory = builder.build(is);
//3.获取SqlSession对象
sqlSession = factory.openSession();
//4.获取UserDao代理对象
accountDao = sqlSession.getMapper(AccountDao.class);
}
/**
* 释放资源
* @throws IOException
*/
@After
public void destroy() throws IOException {
is.close();
sqlSession.close();
}
@Test
public void testFindAll() {
List<Account> accounts = accountDao.findAll();
for (Account account : accounts) {
System.out.println(account);
}
}
}
- UserTest
/**
* 用户表的测试
*
* @author lp
* @version 1.0
*/
public class UserTest {
InputStream is;
SqlSessionFactory factory;
SqlSession sqlSession;
UserDao userDao;
/**
* 初始化
* @throws IOException
*/
@Before
public void init() throws IOException {
//1.读取配置文件
is = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.获取SqlSession工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
factory = builder.build(is);
//3.获取SqlSession对象
sqlSession = factory.openSession();
//4.获取UserDao代理对象
userDao = sqlSession.getMapper(UserDao.class);
}
/**
* 释放资源
* @throws IOException
*/
@After
public void destroy() throws IOException {
is.close();
sqlSession.close();
}
@Test
public void testFindAll() {
List<User> users = userDao.findAll();
for (User user : users) {
System.out.println(user);
}
}
}
6.1.2.多对一
如上所说,在mybatis中,将多对一的情况视作一对一处理
6.1.2-一对多
与上面类似,不同的是要在User实体类上建立一个List集合
//一个用户可以有多个账户
private List<Account> accounts;
6.1.3.多对多
- 添加pom依赖,与上相同
- 建立实体类,两个实体类都需要List集合,此外再建立一个
UserRole
实体类(此类无需tostring方法)
//多对多映射关系:一个角色可以赋予多个用户
private List<User> users;
//一个用户对应多个角色
private List<Role> roles;
/**
* @author lp
* @version 1.0
*/
public class UserRole {
private int uid;
private int rid;
- 建立接口
public interface RoleDao {
/**
* 查询角色列表
* @return
*/
List<Role> findAll();
}
public interface UserDao {
/**
* 查询用户列表
* @return
*/
List<User> findAll();
}
- xml映射配置文件
RoleDao.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.wdzl.dao.RoleDao">
<resultMap id="roleMap" type="role">
<id property="rid" column="rid"/>
<result property="roleName" column="ROLE_NAME"/>
<result property="roleDesc" column="ROLE_DESC"/>
<collection property="users" ofType="user" column="uid">
<id property="uid" column="uid"></id>
<result property="username" column="username"></result>
<result property="birthday" column="birthday"></result>
<result property="sex" column="sex"></result>
<result property="address" column="address"></result>
</collection>
</resultMap>
<!--查询用户列表-->
<select id="findAll" resultMap="roleMap">
select r.*,u.* from role r
left outer join user_role ur on r.`rid`=ur.`RID`
left outer join user u on u.`uid`= ur.`UID`
</select>
</mapper>
UserDao.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.wdzl.dao.UserDao">
<resultMap id="userMap" type="user">
<id property="uid" column="uid"></id>
<result property="username" column="username"></result>
<result property="birthday" column="birthday"></result>
<result property="sex" column="sex"></result>
<result property="address" column="address"></result>
<collection property="roles" ofType="role" column="rid">
<id property="rid" column="rid"/>
<result property="roleName" column="ROLE_NAME"/>
<result property="roleDesc" column="ROLE_DESC"/>
</collection>
</resultMap>
<!--查询用户列表-->
<select id="findAll" resultMap="userMap">
select u.*,r.* from user u
left outer join user_role ur on u.`uid`= ur.`UID`
left outer join role r on r.`rid`=ur.`RID`
</select>
</mapper>
-
主配置文件与上面一对多相同
-
Test
/**
* 用户表的测试
*
* @author lp
* @version 1.0
*/
public class RoleTest {
InputStream is;
SqlSessionFactory factory;
SqlSession sqlSession;
RoleDao roleDao;
/**
* 初始化
* @throws IOException
*/
@Before
public void init() throws IOException {
//1.读取配置文件
is = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.获取SqlSession工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
factory = builder.build(is);
//3.获取SqlSession对象
sqlSession = factory.openSession();
//4.获取UserDao代理对象
roleDao = sqlSession.getMapper(RoleDao.class);
}
/**
* 释放资源
* @throws IOException
*/
@After
public void destroy() throws IOException {
is.close();
sqlSession.close();
}
@Test
public void testFindAll() {
List<Role> roles = roleDao.findAll();
for (Role role : roles) {
System.out.println("----------------------");
System.out.println(role);
System.out.println(role.getUsers());
}
}
}
/**
* 用户表的测试
*
* @author lp
* @version 1.0
*/
public class UserTest {
InputStream is;
SqlSessionFactory factory;
SqlSession sqlSession;
UserDao userDao;
/**
* 初始化
* @throws IOException
*/
@Before
public void init() throws IOException {
//1.读取配置文件
is = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.获取SqlSession工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
factory = builder.build(is);
//3.获取SqlSession对象
sqlSession = factory.openSession();
//4.获取UserDao代理对象
userDao = sqlSession.getMapper(UserDao.class);
}
/**
* 释放资源
* @throws IOException
*/
@After
public void destroy() throws IOException {
is.close();
sqlSession.close();
}
@Test
public void testFindAll() {
List<User> users = userDao.findAll();
for (User user : users) {
System.out.println("--------------------------");
System.out.println(user);
System.out.println(user.getRoles());
}
}
}
7.缓存
概述:存在于内存中的数据叫缓存
应用:减少和数据库的交互,提高执行效率
适用
- 经常查询并且不经常改变的
- 对最终结果影响不大的
不适用:
- 经常改变的数据
- 数据的最终结果对结果影响很大的(银行汇率,股票价格)
分类:mybatis中分为一级缓存和二级缓存
7.1.一级缓存
概述:它指的是MyBatis中的SqlSession对象的缓存,当我们执行查询后,查询结果会存入到SqlSession为我们提供的一款存储区域中,该区域的存储结构为Map,当我们再次查询同样的数据时,Mybatis首先去一级缓存中查询,如果存在,则直接拿取使用
注意:当SqlSession对象消失时,MyBatis的一级缓存也会消失
案例:缓存的案例与之前的区别不大,但要在主配置文件开启懒加载
<!--设置懒加载-->
<settings>
<setting name="lazyLoadingEnabled" value="true"/> <!--开启懒加载-->
</settings>
@Test
public void testFirstLevelCache() {
//执行查询
User user = userDao.findUserById(1);
System.out.println(user);
sqlSession.close();
SqlSession sqlSession2 = factory.openSession();
UserDao userDao2 = sqlSession2.getMapper(UserDao.class);
User user2 = userDao2.findUserById(1);
System.out.println(user2);
System.out.println(user==user2);
}
7.2.二级缓存
概述:它指的是MyBatis中SqlSessionFactory对象的缓存,在同一个SqlSessionFactory对象创建的SqlSession对象 共享二级缓存
开启二级缓存
1.主配置文件中开启二级缓存
<settings>
<setting name="cacheEnabled" value="true"/><!--开启二级缓存-->
</settings>
2.在映射配置文件中开启二级缓存
<!--开启二级缓存-->
<cache/>
3.在映射配置文件标签里添加属性useCache="true"
<!--根据id查询用户-->
<select id="findUserById" parameterType="int" resultType="user" useCache="true">
select * from user where uid=#{uid}
</select>
- 一级缓存和二级缓存的区别1
- 一级缓存是SqlSession对象的缓存
- 二级缓存是SqlSessionFactory对象的缓存(SqlSessionFactory用来生产SqlSession)
- 一级缓存和二级缓存的区别2
- 一级缓存只需要在主配置文件中开启
- 二级缓存却更加复杂,不仅需要在主配置文件中开启,还要在xml映射配置文件中
mappper
标签下的namespace
对应的区域做一个标签和属性