MyBatis
1.概述
MyBatis是一款优秀的持久化框架,支持自定义SQL,存储过程以及高级映射,MyBatis免去了几乎所有的JDBC代码,以及设置参数,获取结果集对象。MyBatis可以通过简单的XML配置或注解来配置映射关系
Hibernate框架:全自动映射ORM框架
2.为什么使用MyBatis
JDBC:
SQL编写在代码中,耦合度比较高
实际开发中SQL会经常被更新,维护不易
Hibernate
内部自动生成SQL,不方便特殊优化
长难复杂的SQL,处理很不容易
基于全映射的全自动框架,进行字段部分映射比较困难,并且会导致数据库性能下降
MyBatis
SQL和JAVA编码分离,功能划分请出,一个专注数据,一个专注业务
核心SQL可以自己编写,优化比较方便
3.MyBatis环境搭建(XML解析入门)
3.1环境搭建
步骤:
1.创建Maven工程,并导入相关依赖
2.创建实体类
3.创建dao层接口
4.创建MyBatis主配置文件:SqlMapConfig.xml
5.创建映射配置文件:UserDao.xml
注意事项:
1.创建directory和package的区别
directory:com.wdzl.dao创建的一级目录
package:com.wdzl.dao创建三级目录
2.MyBatis的映射配置文件所在目录层级要与对应的dao层接口目录层级相同
3.映射配置文件mapper标签namespace属性值必须是对应接口的全线定类名
4.映射配置文件select标签id属性必须与对应的方法名一致,不能随便写
5.只要遵循2,3,4的规定,我萌就不用去写接口类的实现类
-
1.创建Maven工程,并导入相关依赖
<?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>HelloMybatis2</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>
-
2.创建实体类
package com.wdzl.pojo; /** * 学生类 */ public class Student { private int id; private String username; private String gender; private String birthday; private String address; public Student() { } @Override public String toString() { return "Student{" + "id=" + id + ", username='" + username + '\'' + ", gender='" + gender + '\'' + ", birthday='" + birthday + '\'' + ", address='" + address + '\'' + '}'; } 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 getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } public String getBirthday() { return birthday; } public void setBirthday(String birthday) { this.birthday = birthday; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public Student(int id, String username, String gender, String birthday, String address) { this.id = id; this.username = username; this.gender = gender; this.birthday = birthday; this.address = address; } }
-
3.创建dao层接口
package com.wdzl.dao; import com.wdzl.pojo.Student; import java.util.List; /** * 操作用户数据的接口 */ public interface UserDao { /** * 查询所有用户信息 */ List<Student> findAll(); }
-
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"> <environment id="mysql"> <!-- 配置事务的类型 --> <transactionManager type="JDBC"></transactionManager> <!-- 配置数据源--> <dataSource type="POOLED"> <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> <mappers> <mapper resource="com/wdzl/dao/UserDao.xml"></mapper> </mappers> </configuration>
-
5.创建映射配置文件: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"> select*from student; </select> </mapper>
3.2入门测试案例
步骤:
1.读取配置文件
2.创建SqlSessionFactory对象—>通过SqlSessionFactoryBuilder对象获取
3.使用工厂对象生产SqlSession对象
4.使用SqlSession对象获取接口代理对象
5.使用代理对象调用方法
6.释放资源
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gTXoaik7-1616670375501)(D:\图片\8A46D97A-1AEE-47da-BBAA-945612CF9570.png)]
package com.wdzl.dao;
import com.wdzl.pojo.Student;
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;
/**
* UserDao测试类
*
* MyBatis入门案列测试实现步骤
* 1.读取配置文件
* 2.创建SqlSessionFactory工厂
* 3.用工厂生产SqlSession对象
* 4.使用SqlSession对象创建dao层代理对象
* 5.使用代理对象执行方法
* 6.释放资源
*/
public class UserDaoTest {
@Test
public void findAllTest() throws IOException {
//1.读取配置文件
InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.创建SqlSessionFactory工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory =builder.build(resourceAsStream);
//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();
resourceAsStream.close();
}
}
4.MyBatis 注解入门
1.先新建一个Maven工程,将上一个工程的内容都复制到该工程中
2.映射配置文件就不需要了我们可以将它删除掉,并在相应的接
口方法上写上注解即可
package com.wdzl.dao;
import com.wdzl.pojo.Student;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/**
* 操作用户数据的接口
*/
public interface UserDao {
/**
* 查询所有用户信息
*/
@Select("select*from student")
List<Student> findAll();
}
3.修改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">
<environment id="mysql">
<!-- 配置事务的类型 -->
<transactionManager type="JDBC"></transactionManager>
<!-- 配置数据源-->
<dataSource type="POOLED">
<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>
<mappers>
<mapper class="com.wdzl.dao.UserDao"/>
</mappers>
</configuration>
5.自定义MyBatis
5.1分析
MyBatis在使用代理的方式实现增删改查时都做了什么
-
创建代理对象
-
在代理对象中创建方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oiCnzmhL-1616670375504)(D:\图片\QQ截图20210325153443.png)]
由图可知,执行代码需要两组信息
1.连接信息
2.映射信息
执行SQL语句
封装结果的实体类全限定类名
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ke7OWg7X-1616670375511)(D:\图片\QQ截图20210325154024.png)]
5.2自定义MyBatis
1.新建Module
2.将第一个入门案例整体拷贝到改Module中,并在pom.xml中删除Mybatis的依赖信息
3.Resources 类
package com.wdzl.io;
import java.io.InputStream;
/**
*
*/
public class Resources {
public static InputStream getResourceAsStream(String filePath){
return Resources.class.getClassLoader().getResourceAsStream(filePath);
}
}
4.创建SqlSessionFactoryBuilder类
package com.wdzl.SqlSession;
import com.wdzl.SqlSession.imp.SqlSessionFactoryImpl;
import com.wdzl.pojo.Configuration;
import com.wdzl.utils.XMLConfigBuilder;
import java.io.InputStream;
/**
* 创建工厂
*/
public class SqlSessionFactoryBuilder {
public SqlSessionFactory build(InputStream inputStream){
Configuration cfg= XMLConfigBuilder.loadConfiguration(inputStream);
return new SqlSessionFactoryImpl(cfg);
}
}
5.创建SqlSessionFactory接口
package com.wdzl.SqlSession;
public interface SqlSessionFactory {
SqlSession openSession();
}
6.创建SqlSession
package com.wdzl.SqlSession;
/**
* 自定义MyBatis框架核心接口
*/
public interface SqlSession {
/**
* 根据接口创建代理对象
* @param daoInterfaceClass
* @param <T>
* @return
*/
<T> T getMapper(Class<T> daoInterfaceClass);
/**
* 释放资源
*
*/
void close();
}
7.导入XML解析工具类:XMLConfigBuilder 和 相关依赖
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>1.1.6</version>
</dependency>
8.创建Configration类
package com.wdzl.pojo;
import java.util.HashMap;
import java.util.Map;
public class Configuration {
private String driver;
private String url;
private String username;
private String password;
private Map<String,Mapper> mappers=new HashMap<>();
public Map<String, Mapper> getMappers() {
return mappers;
}
public void setMappers(Map<String, Mapper> mappers) {
this.mappers.putAll(mappers);
}
public String getDriver() {
return driver;
}
public void setDriver(String driver) {
this.driver = driver;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
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;
}
}
9.创建Mapper对象
package com.wdzl.pojo;
/**
* 用于封装执行的sql语句和结果类型的全限定类型的类
*/
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;
}
}
10.在 Configuration 中添加成员变量: Mappers
private Map<String,Mapper> mappers=new HashMap<>();
11.回到 SqlSessionFactoryBuilder 编写 build 方法
return new SqlSessionFactoryImpl(cfg);
-
新建 SqlSessionFactoryImpl 实现类,实现 SqlSessionFactory 接口
package com.wdzl.SqlSession.imp; import com.wdzl.SqlSession.SqlSession; import com.wdzl.SqlSession.SqlSessionFactory; import com.wdzl.pojo.Configuration; public class SqlSessionFactoryImpl implements SqlSessionFactory { private Configuration cfg; public SqlSessionFactoryImpl(Configuration cfg){ this.cfg=cfg; } @Override public SqlSession openSession() { return new SqlSessionImpl(cfg); } }
13.创建 SqlSession 的实现类对象: SqlSessionImpl
package com.wdzl.SqlSession.imp;
import com.wdzl.SqlSession.SqlSession;
import com.wdzl.pojo.Configuration;
import com.wdzl.proxy.MapperProxy;
import com.wdzl.utils.DataSourceUtil;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.SQLException;
public class SqlSessionImpl implements SqlSession {
private Configuration cfg;
private Connection connection;
public SqlSessionImpl(Configuration cfg){
this.cfg=cfg;
connection= DataSourceUtil.getConnection(cfg);
}
@Override
public <T> T getMapper(Class<T> daoInterfaceClass) {
return (T) Proxy.newProxyInstance(daoInterfaceClass.getClassLoader(),
new Class[]{daoInterfaceClass},
new MapperProxy(cfg.getMappers(),connection));
}
@Override
public void close() {
try {
connection.close();
} catch (SQLException sqlException) {
sqlException.printStackTrace();
}
}
}
-
使用动态代理实现getMapper()方法
@Override public <T> T getMapper(Class<T> daoInterfaceClass) { return (T) Proxy.newProxyInstance(daoInterfaceClass.getClassLoader(), new Class[]{daoInterfaceClass}, new MapperProxy(cfg.getMappers(),connection)); }
15.创建InvocationHandler接口的实现类:MapperProxy
package com.wdzl.proxy;
import com.wdzl.pojo.Mapper;
import com.wdzl.utils.Executor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.util.Map;
public class MapperProxy implements InvocationHandler {
private Map<String, Mapper> mappers;
private Connection connection;
public MapperProxy(Map<String,Mapper> mappers,Connection connection){
this.mappers=mappers;
this.connection=connection;
}
/**
* 用于增强findAll()方法
* @param proxy
* @param method
* @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().getName();
//3.组装key
String key=className+"."+methodName;
//4.获取mapper对象
Mapper mapper = mappers.get(key);
//判断是否存在
if (mapper==null){
throw new IllegalAccessException("传入数据异常");
}
//6.执行
return new Executor().selectList(mapper,connection);
}
}
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);
}
}
}
17.测试
package com.wdzl.dao;
import com.wdzl.io.Resources;
import com.wdzl.pojo.Student;
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;
/**
* UserDao测试类
*
* MyBatis入门案列测试实现步骤
* 1.读取配置文件
* 2.创建SqlSessionFactory工厂
* 3.用工厂生产SqlSession对象
* 4.使用SqlSession对象创建dao层代理对象
* 5.使用代理对象执行方法
* 6.释放资源
*/
public class UserDaoTest {
@Test
public void findAllTest() throws IOException {
//1.读取配置文件
InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.创建SqlSessionFactory工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory =builder.build(resourceAsStream);
//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();
resourceAsStream.close();
}
}
6.MyBatis-CRUD操作
测试前准备工作
@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();
}
6.1查询
1. 在UserDao中添加方法
/**
* 查询
* @return
*/
List<User> findAll();
2.在UserDao.xml中配置该方法
<select id="findAll" resultMap="userMap">
select*from user;
</select>
3.编写测试类
@Test
public void findAllTest() throws IOException {
//5.使用代理对象执行方法
List<User> users = userDao.findAll();
//遍历
for (User user:users){
System.out.println(user);
}
}
6.2添加
1.在UserDao中添加方法
/**
* 添加用户
* @param user
*/
void addUser(User user);
2.在UserDao.xml中配置该方法
<!--添加用户-->
<insert id="addUser" parameterType="com.wdzl.pojo.User">
insert into user (username,birthday,sex,address) values (#{username},#{birthday},#{sex},#{address});
</insert>
3.编写测试类
@Test
public void addUserTest() throws IOException {
User user=new User("赵童","2000-02-18","男","宝鸡",5);
// //4.使用SqlSession对象创建dao层代理对象
// userDao = sqlSession.getMapper(UserDao.class);
//5.使用代理对象执行方法
userDao.addUser(user);
System.out.println(user);
System.out.println("----------------------------------------");
//6.开启事务
sqlSession.commit();
System.out.println(user);
}
注意:取值这里有两种方式#{} 和 ${}
- #{} : 采取预编译方式
- ${}:采取字符串拼接
6.3修改
1.在UserDao中添加方法
/**
* 修改信息
*/
void updateUser(User user);
2.在UserDao.xml中配置该方法
<!--修改信息-->
<update id="updateUser" parameterType="com.wdzl.pojo.User">
update user set address=#{address} where username=#{username}
</update>
3.编写测试类
@Test
public void testUpdateUser(){
User user=new User();
user.setUsername("%童");
user.setAddress("西安");
List<User> userByName = userDao.findUserByName("%童");
//5.使用代理对象执行方法
List<User> users = userDao.findAll();
//遍历
for (User user2:userByName){
System.out.println(user2);
}
}
6.4删除
1.在UserDao中添加方法
/**
* 删除
*/
void deleteUser(User user);
2.在UserDao.xml中配置该方法
<!--删除信息-->
<delete id="deleteUser" parameterType="com.wdzl.pojo.User">
delete from user where username=#{username};
</delete>
3.编写测试类
@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);
}
}
6.5根据id查询用户信息
1.在UserDao中添加方法
/**
* 根据id查询用户信息
*/
User findUserById(int id);
2.在UserDao.xml中配置该方法
<!--根据id查询用户信息-->
<select id="findUserById" parameterType="java.lang.Integer" resultType="com.wdzl.pojo.User">
select *from user where id=#{id};
</select>
3.编写测试类
@Test
public void testFindUserById(){
User user=userDao.findUserById(3);
System.out.println(user);
}
6.6模糊查询
1.在UserDao中添加方法
/**
* 模糊查询
*
*/
List<User> findUserByName(String name);
2.在UserDao.xml中配置该方法
<!--模糊查询-->
<select id="findUserByName" parameterType="String" resultType="com.wdzl.pojo.User">
select * from user where username like #{username};
</select>
3.编写测试类
@Test
public void testUpdateUser(){
User user=new User();
user.setUsername("%童");
user.setAddress("西安");
List<User> userByName = userDao.findUserByName("%童");
//5.使用代理对象执行方法
List<User> users = userDao.findAll();
//遍历
for (User user2:userByName){
System.out.println(user2);
}
}
6.7查询用户总记录数
1.在UserDao中添加方法
/**
* 查询用户总记录数
*/
int findTotal();
2.在UserDao.xml中配置该方法
<!-- 查询用户总记录数-->
<select id="findTotal" resultType="int" >
select count(id) from user;
</select>
3.编写测试类
@Test
public void testFindTotal(){
int total = userDao.findTotal();
System.out.println(total);
}
6.8根据QueryVo查询用户信息
1.在UserDao中添加方法
/**
* 根据QueryVo查询用户信息
*/
List<User> findUserByVo(QueryVo queryVo);
2.在UserDao.xml中配置该方法
<!--根据包装类模糊查询用户数据信息-->
<select id="findUserByVo" parameterType="com.wdzl.pojo.QueryVo" resultType="com.wdzl.pojo.User">
select*from user where username like #{user.username}
</select>
3.编写测试类
@Test
public void testFindByVo(){
QueryVo queryVo=new QueryVo();
User user=new User();
user.setUsername("%德%");
queryVo.setUser(user);
List<User> userByVo = userDao.findUserByVo(queryVo);
for (User user1:userByVo){
System.out.println(user1);
}
}
keyProperty : 对应的实体类属性名
keyColumn :对应数据库列名
Order : 执行的顺序,after-在插入操作后执行
7.参数详解
7.1parameterType 输入类型
-
传递基本数据类型和 String
-
传递pojo对象
当传递参数为对象时,在sql语句中获取对象属性值需要使用OGNL表达式。
- OGNL:Object Graphic Navigation Language 对象图导航语言
- 它是通过对象的取值方式来获取值,在写法上把get给省略了
- 在类中,我们获取值:user.getUsername();
- 在OGNL中:user.userName
- Mybatis中为什么能直接写userName,而不加 user. 呢?
- 因为在 parameterType 中已经提供了属性所属的类,所以可以省略类名
7.2实体类属性与表字段不对应的问题解决
方案1:统一实体类和表字段的名称
方案2:给数据库字段加别名 ,让别名与实体类属性名统一
select id as userId
方案3:在UserDao.xml中配置对应关系
<resultMap id="userMap" type="com.wdzl.pojo.User">
<id property="uid" column="id"></id>
<result property="username" column="username"></result>
</resultMap>
8.MyBatis实现Dao层的开发
准备:
新建工程,将前面演示CRUD操作的工程内容复制到该工程中,并做对应的修改
- 复制 main 和 test 目录
- 修改 pom.xml ,把相关依赖添加到配置文件中
- 删除 UserDao 中的 ,并将下面标签中使用到 的地方换成
resultType="User"
8.1查询所有的方法(及其他操作)
1.添加UserDao对应的实现类
package com.wdzl.dao.impl;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import com.wdzl.dao.UserDao;
import com.wdzl.pojo.QueryVo;
import com.wdzl.pojo.User;
import java.util.List;
public class UserDaoImpl implements UserDao {
private SqlSessionFactory factory;
private SqlSession sqlSession;
public UserDaoImpl(){
}
public UserDaoImpl(SqlSessionFactory factory){
this.factory=factory;
sqlSession=factory.openSession();
}
/**
* 查询用户列表
* @return
*/
@Override
public List<User> findAll() {
//2.调用sqlSession方法
List<User> users=sqlSession.selectList("com.wdzl.dao.UserDao.findAll");
return users;
}
@Override
public void addUser(User user) {
//2.调用方法
sqlSession.insert("com.wdzl.dao.UserDao.addUser",user);
//3.提交事务
sqlSession.commit();
//4.释放资源
sqlSession.close();
}
@Override
public void updateUser(User user) {
sqlSession.update("com.wdzl.dao.UserDao.updateUser",user);
//3.提交事务
sqlSession.commit();
//4.释放资源
sqlSession.close();
}
@Override
public void deleteUser(User user) {
sqlSession.delete("com.wdzl.dao.UserDao.deleteUser",user);
//3.提交事务
sqlSession.commit();
//4.释放资源
sqlSession.close();
}
@Override
public User findUserById(int id) {
User user=sqlSession.selectOne("com.wdzl.dao.UserDao.findUserById",id);
return user;
}
@Override
public List<User> findUserByName(String name) {
List<User> user = sqlSession.selectList("com.wdzl.dao.UserDao.findUserByName",name);
return user;
}
@Override
public int findTotal() {
Integer total=sqlSession.selectOne("com.wdzl.dao.UserDao.findTotal");
return total;
}
@Override
public List<User> findUserByVo(QueryVo queryVo) {
return null;
}
}
2.测试
package com.wdzl.dao;
import com.wdzl.dao.impl.UserDaoImpl;
import com.wdzl.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class UserDaoTest {
InputStream is;
SqlSessionFactoryBuilder builder;
SqlSessionFactory factory;
@Before
public void init() throws IOException {
//1.读取配置文件
is = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.创建SqlSessionFactory工厂
builder = new SqlSessionFactoryBuilder();
factory =builder.build(is);
}
@After
public void destroy() throws IOException {
is.close();
}
@Test
public void findAllTest() {
UserDao userDao=new UserDaoImpl(factory);
List<User> all = userDao.findAll();
for (User a:all){
System.out.println(a);
}
}
@Test
public void testAddUser(){
User user = new User("唐康","2000-1-1","男","安康",0);
UserDao userDao=new UserDaoImpl(factory);
userDao.addUser(user);
}
@Test
public void testUpdateUser(){
User user = new User("唐康","2000-1-1","男","西安",0);
UserDao userDao=new UserDaoImpl(factory);
userDao.updateUser(user);
}
@Test
public void deleteUser(){
User user = new User("唐康",null,null,null,0);
UserDao userDao=new UserDaoImpl(factory);
userDao.updateUser(user);
}
@Test
public void testFindUserById(){
UserDao userDao = new UserDaoImpl(factory);
User user=userDao.findUserById(2);
System.out.println(user);
}
@Test
public void testFindUserByName(){
UserDao userDao = new UserDaoImpl(factory);
List<User> user2 = userDao.findUserByName("赵童");
for (User user1:user2){
System.out.println(user1);
}
}
@Test
public void testFindTotal(){
UserDao userDao = new UserDaoImpl(factory);
int total = userDao.findTotal();
System.out.println(total);
}
}
9.properties标签
方式一:font>将配置提取出来进行统一管理,在需要使用的地方使用 ${} 引用即可
提取:
<properties>
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</properties>
引用:
<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>
方式二:引用外部配置文件
<properties resource="jdbc.properties"/>
引用外部有两个属性:
- resource : 用于指定配置文件的位置类路径的写法,并且必须存在于类路径下
- url : 统一资源定位符。可以标识资源的位置
10.typeAliases标签 和 package标签
<!--应用外部文件配置别名-->
<typeAliases>
<package name="com.wdzl.pojo"/>
<!-- <typeAlias type="com.wdzl.pojo.User" alias="aa"></typeAlias>-->
</typeAliases>
在 typeAliases 中 有两个属性
- type:用来指定起别名的实体类,如果省略 alias 属性,则使用默认别名,默认别名为类名 ,不区 分大小写,任意组合都可识别
- alias:指定一个新的别名,比如上图案例中将别名设置为 hehe ,则在下面使用时使用 hehe 即可表 示User类。新的别名也不区分大小写
当实体类比较多时,我们可以使用 package 标签批量给包中的类添加别名
11.连接池
11.1概述
连接池就是用于存储连接对象的一个容器,当系统初始化完成后,容器被创建,容器会申请一些连 接对象,当用户访问数据库时,从容器中获取连接对象即可。访问完之后,会将连接对象归还给连接 池。这样做可以提高效率,提高连接对象的复用,不必频繁的创建和释放连接对象
11.22 MyBatis连接池
连接池有很多种,最为熟悉的比如c3p0,DBCP,druid等。
MyBatis支持三种内置的数据源类型:
POOLED: 实现dataSource接口,并且使用了池的思想。
UNPOOLED: 同样也是实现了dataSource接口,但是该类型并没有使用池的思想。
JDNI: 采用服务器提供的JDNI技术实现的,并且在不同服务器之间获取的连接池是不一样的。
当前框架教学使用的是Tomcat服务器,采用的是dbcp连接池技术
12.事务
对于事务的控制后期我们主要依赖于Spring来完成,当然MyBatis本身也是可以对事物进行控制 的。我们查看演示案例执行 addUser 方法时,我们会发现,Mybatis框架 默认事务提交方式是手动的。
我们可以通过 SqlSession 的构造方法进行设置操作。
session = factory.openSession(true);
再次执行 addUser() ,此时事务就会自动被提交。
13.动态SQL
13.1if标签
<!--根据给定条件 完成复合查询-->
<select id="findUserByConditions" parameterType="user" resultType="User">
select * from user where 1=1
<if test="username !=null">
and username=#{username}
</if>
</select>
13.2where标签
where标签是为了解决拼接sql时需要添加一个恒等式的问题
<where>
<if test="ids !=null and ids.size()>0">
<foreach collection="ids" open="and id in (" close=")" item="id" separator=",">
#{id}
</foreach>
</if>
</where>
13.3foreach标签
<foreach collection="集合名" open="and id in (" close=")" item="变量名"
separator="分隔符">
#{变量名}
</foreach>
<foreach collection="ids" open="and id in (" close=")" item="id" separator=",">
#{id}
</foreach>
collection:遍历的集合
open:拼接SQL以该属性值为开头
close:拼接SQL以该属性值为结尾
item:变量名,相当于增强for循环中的那个变量。拼接在 open 和 close 之间
separator:元素(变量)间以什么分割
#{变量名}:必须与 item 属性保持一致
扩展标签
当配置文件中的相同的sql比较多时,我们可以将它统一提取出来
<sql id="userBase">
select * from user
</sql>
<select id="findAll" resultType="user"><!--id属性对应方法的名称,不能随便写 -->
<include refid="userBase"></include>
/* select * from user;*/
</select>
14.MyBatis的多表查询
14.1MyBatis中的多表查询-多对一,一对多
1.数据库表:用户表 和 账户表
CREATE DATABASE mybatis2 CHARSET utf8;
USE mybatis2;
CREATE TABLE `user` (
`id` INT(10) NOT NULL AUTO_INCREMENT,
`username` VARCHAR(64) NOT NULL COMMENT '用户名称',
`birthday` DATETIME DEFAULT NULL COMMENT '生日',
`sex` CHAR(1) DEFAULT NULL COMMENT '性别',
`address` VARCHAR(256) DEFAULT NULL COMMENT '地址',
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO `user`(`id`,`username`,`birthday`,`sex`,`address`)
VALUES
(NULL,'老王','2017-05-27 18:27:09','男','北京'),
(NULL,'小王','2019-04-03 15:09:37','女','西安'),
(NULL,'小李','2019-07-22 17:44:33','女','咸阳'),
(NULL,'小刘','2018-03-04 15:52:36','男','渭南'),
(NULL,'大王','2016-11-03 17:37:26','男','富平'),
(NULL,'小马','2016-04-09 01:24:40','女','上海');
CREATE TABLE `account` (
`ID` INT(11) NOT NULL COMMENT '编号',
`UID` INT(11) DEFAULT NULL COMMENT '用户编号',
`MONEY` DOUBLE DEFAULT NULL COMMENT '金额',
PRIMARY KEY (`ID`),
KEY `FK_Reference_8` (`UID`),
CONSTRAINT `FK_Reference_8` FOREIGN KEY (`UID`) REFERENCES `user` (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO `account`(`ID`,`UID`,`MONEY`) VALUES (1,2,1000),(2,1,1000),
(3,2,2000);
2.创建主配置文件:SqlMapConfig.xml,并且将log4j,jdbc的配置文件一起复制到 resources 目录下
<?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"/>
<typeAliases>
<package name="com.wdzl.pojo"/>
</typeAliases>
<environments default="mysql">
<!--配置mysql环境-->
<environment id="mysql">
<!--配置事务的类型-->
<transactionManager type="JDBC"></transactionManager>
<!--配置数据源(连接池)-->
<dataSource type="POOLED"><!--Pooled 使用连接池-->
<!--配置连接数据库的4个基本信息-->
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<!--指定映射配置文件的位置,映射配置文件指的是每个dao独立的配置文件-->
<mappers>
<mapper resource="com/wdzl/dao/UserDao.xml"/>
<mapper resource="com/wdzl/dao/AccountDao.xml"/>
</mappers>
</configuration>
3.建立两个实体类:用户实体类 和 账户实体类
User:
package com.wdzl.pojo;
import java.util.Date;
import java.util.List;
public class User {
private int uid;
private String username;
private Date birthday;
private char sex;
private String address;
//一个用户可以有多个账户
private List<Account> accounts;
@Override
public String toString() {
return "User{" +
"uid=" + uid +
", username='" + username + '\'' +
", birthday=" + birthday +
", sex=" + sex +
", address='" + address + '\'' +
", accounts=" + accounts +
'}';
}
public int getUid() {
return uid;
}
public void setUid(int uid) {
this.uid = uid;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public List<Account> getAccounts() {
return accounts;
}
public void setAccounts(List<Account> accounts) {
this.accounts = accounts;
}
public User(int uid, String username, Date birthday, char sex, String address, List<Account> accounts) {
this.uid = uid;
this.username = username;
this.birthday = birthday;
this.sex = sex;
this.address = address;
this.accounts = accounts;
}
public User() {
}
}
Account:
package com.wdzl.pojo;
public class Account {
private int aid;
private int uid;
private double money;
//一个账户只属于一个用户
private User user;
@Override
public String toString() {
return "Account{" +
"aid=" + aid +
", uid=" + uid +
", money=" + money +
", user=" + user +
'}';
}
public int getAid() {
return aid;
}
public void setAid(int aid) {
this.aid = aid;
}
public int getUid() {
return uid;
}
public void setUid(int uid) {
this.uid = uid;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Account(int aid, int uid, double money, User user) {
this.aid = aid;
this.uid = uid;
this.money = money;
this.user = user;
}
public Account() {
}
}
4.创建各自实体类操作的接口
UserDao
package com.wdzl.dao;
import com.wdzl.pojo.User;
import java.util.List;
public interface UserDao {
List<User> findAll();
}
AccountDao
package com.wdzl.dao;
import com.wdzl.pojo.Account;
import java.util.List;
/**
* 查询账户列表
*/
public interface AccountDao {
List<Account> findAll();
}
5.创建各接口对应的映射配置文件
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层的全限定类名-->
<resultMap id="UserAccountMap" 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="accounts" ofType="account" column="uid">
<id property="aid" column="aid"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
</collection>
</resultMap>
<!--查询用户列表-->
<select id="findAll" resultMap="UserAccountMap">
SELECT * FROM USER u LEFT OUTER JOIN account a ON u.uid=a.uid
</select>
</mapper>
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" column="uid" javaType="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>
</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 a.uid = u.uid
</select>
</mapper>
6.将映射配置文件添加到主配置文件中
<mappers>
<mapper resource="com/wdzl/dao/UserDao.xml"/>
<mapper resource="com/wdzl/dao/AccountDao.xml"/>
</mappers>
7.测试:分别测试UserDao 和 AccountDao
UserTest
import com.wdzl.dao.AccountDao;
import com.wdzl.dao.UserDao;
import com.wdzl.pojo.Account;
import com.wdzl.pojo.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.apache.log4j.lf5.util.Resource;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class UserTest {
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 testFindAll(){
List<User> all = userDao.findAll();
for (User all1:all){
System.out.println(all1);
}
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qmzu7P5L-1616670375516)(D:\图片\QQ截图20210325182004.png)]
AccountTest
import com.wdzl.dao.AccountDao;
import com.wdzl.dao.UserDao;
import com.wdzl.pojo.Account;
import com.wdzl.pojo.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.apache.log4j.lf5.util.Resource;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class UserTest {
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 testFindAll(){
List<User> all = userDao.findAll();
for (User all1:all){
System.out.println(all1);
}
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PsPMdZqm-1616670375517)(D:\图片\QQ截图20210325182101.png)]
14.2 MyBatis中的多表查询-2 多对多
SQL中多对多的关系需要借助一张中间
需求:查询角色信息的同时显示赋予该角色的用户信息
步骤: 1. 建立两张表,用户表 和 角色表
让用户表和角色表具有多对多的关系。需要使用中间表,中间表中包含这两张表的主键,并 且这两个主键在中间表中是外键
-
建立两个实体类:用户实体类 和 角色实体类
让用户和角色实体类能体现出多对多的关系:各自包含对方的一个集合引用
-
建立配置文件
用户配置文件
角色配置文件
-
实现配置
查询用户时,可以同时得到该用户所包含的角色信息。
当我们查询角色时,可以同时得到拥有该角色的用户信息。
-
实现:先实现单表查询,再实现多对多关系查询
1.新建Module, 修改pom.xml,添加相应依赖
2.将多表查询1的Module中 src下的内容拷贝到当前Module中
3.将 Account有关的类,接口 ,配置文件等进行删除
实体类
接口
AccountDao配置文件
User实体类中与Account有关的属性和方法
UserDao.xml中有关Account的配置信息
测试类:Account测试类 和 User测试类中有关Account的部分
4.创建数据库表并插入数据
CREATE TABLE `role` (
`rid` INT(11) NOT NULL COMMENT '编号',
`ROLE_NAME` VARCHAR(30) DEFAULT NULL COMMENT '角色名称',
`ROLE_DESC` VARCHAR(60) DEFAULT NULL COMMENT '角色描述',
PRIMARY KEY (`rid`)5. 创建实体类
注意:本次实体类的属性名和表字段并没有匹配,所以我们需要去手动配置映射
) ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO `role`(`rid`,`ROLE_NAME`,`ROLE_DESC`) VALUES (1,'院长','管理整个学
院'),(2,'总裁','管理整个公司'),(3,'校长','管理整个学校');
CREATE TABLE `user_role` (
`UID` INT(11) NOT NULL COMMENT '用户编号',
`RID` INT(11) NOT NULL COMMENT '角色编号',
PRIMARY KEY (`UID`,`RID`),
KEY `FK_Reference_10` (`RID`),
CONSTRAINT `FK_Reference_10` FOREIGN KEY (`RID`) REFERENCES `role` (`rid`),
CONSTRAINT `FK_Reference_9` FOREIGN KEY (`UID`) REFERENCES `user` (`uid`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO `user_role`(`UID`,`RID`) VALUES (1,1),(3,1),(1,2);
5.创建实体类
Role:
package com.wdzl.pojo;
import java.util.List;
public class Role {
private int rid;
private String roleName;
private String roleDesc;
@Override
public String toString() {
return "Role{" +
"rid=" + rid +
", roleName='" + roleName + '\'' +
", roleDesc='" + roleDesc + '\'' +
", users=" + users +
'}';
}
public List<User> getUsers() {
return users;
}
public void setUsers(List<User> users) {
this.users = users;
}
//一个角色可以赋予多个用户
private List<User> users;
public int getRid() {
return rid;
}
public void setRid(int rid) {
this.rid = rid;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
public String getRoleDesc() {
return roleDesc;
}
public void setRoleDesc(String roleDesc) {
this.roleDesc = roleDesc;
}
public Role(int rid, String roleName, String roleDesc) {
this.rid = rid;
this.roleName = roleName;
this.roleDesc = roleDesc;
}
public Role() {
}
}
6.创建Dao接口
public interface RoleDao {
/**
* 查询所有角色
*/
List<Role> findAll();
}
7.创建映射配置文件
<?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"><!--对应dao的全限定类名-->
<resultMap id="roleMap" type="com.wdzl.pojo.Role">
<id property="roleId" column="rid"></id>
<result property="roleName" column="ROLE_NAME"></result>
<result property="roleDesc" column="ROLE_DESC"></result>
</resultMap>
<select id="findAll" resultMap="roleMap">
select * from role
</select>
</mapper>
8.主配置文件中添加相应的映射文件配置
<mapper resource="com/wdzl/dao/RoleDao.xml"/>
9.测试单表查询是否成功
import com.wdzl.dao.RoleDao;
import com.wdzl.dao.UserDao;
import com.wdzl.pojo.Role;
import com.wdzl.pojo.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.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class RoleTest {
InputStream is;
SqlSessionFactoryBuilder builder;
SqlSessionFactory factory;
SqlSession sqlSession;
RoleDao roleDao;
@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层代理对象
roleDao = sqlSession.getMapper(RoleDao.class);
}
@After
public void destroy() throws IOException {
sqlSession.close();
is.close();
}
@Test
public void testFindAll(){
List<Role> all = roleDao.findAll();
for (Role all1:all){
System.out.println(all1);
}
}
}
10.多对多关系在实体类中进行体现
//一个角色可以赋予多个用户
private List<User> users;
11.分析SQL语句
12.测试
/**
* 查询角色
*/
@Test
public void testFindAllUser() {
List<Role> roles = roleDao.findAll();
for (Role role : roles) {
System.out.println(role);
System.out.println(role.getUsers());
}
}
15.延迟加载
延迟加载和立即加载
延迟加载:在真正使用的时候才发起查询,不用的时候不查询。延迟加载也可以称为按需加载或懒加载。
立即加载:无论数据是否使用,只要调用方法,就会立马执行查询
<settings>
<setting name="lazyLoadTriggerMethods" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
16.缓存
概述:
存在于内存中的数据叫做缓存
应用:
减少和数据库的交互,提高执行效率
适用:
经常查询并且不经常改变的。
数据的正确与否对最终结果影响不大的。(比如视频访问量,回帖数量等)
不适用:
经常改变的数据
数据的正确与否对最终结果影响很大时(银行汇率,股票价格)
分类:
MyBatis中分为 一级缓存 和 二级缓存
16.1一级缓存
概述:
它指的是MyBatis中SqlSession对象的缓存。当我们执行查询后,查询结果会存入到SqlSession为我 们提供的一款存储区域中。该区域的存储结构为Map。当我们再次查询同样数据时,MyBatis首先去一 级缓存中查询,如果存在,则直接拿取使用
注意:
当SqlSession对象消失时,MyBatis的一级缓存也会消失
当sqlSession调用 add , update , delete,commit , close方法时,MyBatis会自动清空一级缓存,防 止缓存数据与数据库中的数据不一致。
16.2二级缓存
概述:
它指的是MyBatis中SqlSessionFactory对象的缓存。由同一个SqlSessionFactory对象创建的 SqlSession对象共享二级缓存。
17.MyBatis的注解开发
注意:
注解开发是为了简化映射配置文件,但是主配置文件还是存在。
环境搭建:
1.新建Module
2.修改pom.xml,添加相应的依赖
3.创建实体类User
4.创建主配置文件:SqlSessionConfig.xml
- 引入外部配置文件
- 配置别名
- 配置数据源
- 指定带有注解的dao层接口所在位置
5.创建UserDao
- 声明findAll()方法
- 在该方法上使用注解@Select
6.测试
- 读取配置文件
- 获取SqlSessionFactory对象
- 使用Factory生成SqlSession
- 使用SqlSession生成代理对象
- 调用方法
- 释放资源
7.注意事项:
采用注解开发时,如果对应目录下还存在配置文件,及时在主配置文件中没有配置 xml ,运行时也会 报错。
- 删除配置文件
- 将配置文件移动到其他目录下
注解分类:
- @Select
- @Insert
- @Delete
- @Update
17.1注解一对多案例
接口
UserDao接口
package com.wdzl.dao;
import com.wdzl.pojo.User;
import org.apache.ibatis.annotations.Many;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.mapping.FetchType;
import java.util.List;
public interface UserDao {
@Select("select*from user")
@Results(id="userMap",value = {
@Result(id = true,property = "uid",column = "uid"),
@Result(property = "username",column = "username"),
@Result(property = "birthday",column = "birthday"),
@Result(property = "sex",column = "sex"),
@Result(property = "address",column = "address"),
@Result(property = "accounts",column = "uid",many = @Many(select = "com.wdzl.dao.AccountDao.findAccountByUid",
fetchType = FetchType.EAGER
))
})
List<User> findAll();
@Select("select * from user where uid=#{uid}")
User findUserByUid(Integer uid);
}
Account接口
package com.wdzl.dao;
import com.wdzl.pojo.Account;
import org.apache.ibatis.annotations.One;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.mapping.FetchType;
import java.util.List;
/**
* 查询账户列表
*/
public interface AccountDao {
@Select("select * from account")
@Results(id="accountMap",value = {
@Result(id=true,column = "aid",property = "aid"),
@Result(column = "uid",property = "uid"),
@Result(column = "money",property = "money"),
@Result(column = "uid",property = "user",one=@One(
select="com.wdzl.dao.UserDao.findUserByUid",
fetchType = FetchType.EAGER
))
})
List<Account> findAll();
@Select("select*from account where uid=#{uid}")
Account findAccountByUid(Integer uid);
}
测试
UserTest
import com.wdzl.dao.AccountDao;
import com.wdzl.dao.UserDao;
import com.wdzl.pojo.Account;
import com.wdzl.pojo.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.apache.log4j.lf5.util.Resource;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class UserTest {
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 testFindAll(){
List<User> all = userDao.findAll();
for (User all1:all){
System.out.println(all1);
}
}
@Test
public void testFindUserById(){
User user= userDao.fin00dUserByUid(2);
System.out.println(user);
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gkwv6M2S-1616670375518)(D:\图片\QQ截图20210325190128.png)]
AccountTest
import com.wdzl.dao.AccountDao;
import com.wdzl.dao.UserDao;
import com.wdzl.pojo.Account;
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.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class AccountTest {
InputStream is;
SqlSessionFactoryBuilder builder;
SqlSessionFactory factory;
SqlSession sqlSession;
AccountDao accountDao;
@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层代理对象
accountDao = sqlSession.getMapper(AccountDao.class);
}
@After
public void destroy() throws IOException {
sqlSession.close();
is.close();
}
@Test
public void testFindALL(){
List<Account> all = accountDao.findAll();
for (Account account:all){
System.out.println(account);
}
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LWXPBGjg-1616670375519)(D:\图片\QQ截图20210325190220.png)]