Mybatis框架
一. 引言
1.为什么使用mybatis
目前使用开发遇到的问题
问题一:每一个操作对应的使用Dao中的方法,内一个方法中都需要连接数据库,这样我们连接数据库的代码就需要些好多次
问题二:如果我们做的是查询的操作,从rs中取值是一个比较麻烦而且影响开发效率的问题
解决方案:
1.提取DBUtil工具类即可
优点:不用再每一次写连接数据库操作的代码
缺点:传统的JDBC连接数据库的效率非常的慢
2.使用数据库连接池连接数据库
优点:连接数据库的速度比较快
缺点:没有办法实现SQL语句和java代码之间的解耦
3.使用mybatis框架
作用: 1) 解决了SQL语句和java代码之间的耦合
2) 连接数据库的效率也比较快
3) 取值问题就会变得非常的简单
2.什么是框架?
框架就是别人封装好的代码,我们直接拿来用就好
框架的体现形式就是jar包。我们自己写好的代码也可以打成jar包,别人也可以使用。
(jar包 API 源码)
3.什么是Mybatis框架
Mybatis 是apache的一个开源项目IBatis,2010年这个项目由apache software foundation迁移到了google code,并且改名为Mybatis.2013年11月迁移到Github
IBATIS一词来源于"Internet "和"abatis"的组合,是一个基于Java的持久层框架.
iBATIS提供的持久层框架包括SQL MAPs 和Data Access Objects(DAOs)。
Mybatis是一个半自动化的ORM框架
那什么又是ORM呢?
ORM : Object Relational Mapping (作用解决数据库发展和面向对象发展不一致的问题)
O : 面向对象
R : 关系型数据库 >> MySql ,Oracal
M : 映射
半自动化 : mybatis框架是需要我们自己动手写sql语句
Mybatis框架不依赖于服务器的,所以它有以下的优点。
优点:
A. 连接数据库速度快
B. 实现了SQL语句和JAVA代码之间的解耦
C. 数据库的查询取值非常方便
二. 环境搭建
了解了MyBatis框架,那就来试试如何去使用它吧!
步骤:
-
创建一个Maven项目
-
书写配置SqlConfig.xml文件
-
配置UserDao.xml文件
-
书写测试代码
* 1.加载主配置文件 * 2.创建SqlSessionFactory工厂 * 3.使用SessionFactory工厂生产SqlSession对象 * 4.执行方法 * 5.释放资源
pom.xml配置文件:导入坐标
<?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>org.example</groupId>
<artifactId>mybatis_demo3</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!--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>8.0.25</version>
</dependency>
<!--单元测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
</dependency>
</dependencies>
</project>
SqlConfig.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">
<!--Mybatis的主配置文件-->
<configuration>
<!-- 配置环境-->
<environments default="development">
<!-- 配置mysql环境-->
<environment id="development">
<!-- 配置事务的类型-->
<transactionManager type="JDBC"/>
<!-- 配置数据源(连接池)-->
<dataSource type="POOLED">
<!-- 配置连接数据库的4个基本信息-->
< 标签内配置连接数据库的信息 >
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis_db"/>
<property name="username" value="root"/>
<property name="password" value="123"/>
</dataSource>
</environment>
</environments>
<!-- 指定映射文件的位置
进行mapper文件的扫描 >> resource:书写的是xml文件所在的目录
-->
<mappers>
<mapper resource="cn/dao/UserDao.xml"></mapper>
</mappers>
</configuration>
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="cn.lmx.UserDao">
<!-- eg:select
List<User> findAll();
id : 方法名称
resultType : 返回值类型
查询返回的时候不是对象就是集合. 如果返回值是一个对选哪个,就写对象所在包的全路径 ; 如果返回值是一个集合,就写集合的泛型
-->
<!--查询所有信息-->
<select id="findAll" resultType="cn.pojo.User">
select * from user
</select>
</mapper>
测试代码:
package test;
import cn.dao.UserDao;
import cn.pojo.QueryUser;
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 cn.pojo.User;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;
/**
* 1.加载主配置文件
* 2.创建SqlSessionFactory工厂
* 3.使用SessionFactory工厂生产SqlSession对象
* 4.执行方法
* 5.释放资源
*/
public class UserTest {
/**
* 查询所有信息
* @throws IOException
*/
@Test
public void testUser() throws IOException {
//1.加载/读取配置文件
InputStream is = Resources.getResourceAsStream("SqlConfig.xml");
//2.创建工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(is);
//3.使用工厂生产对象
SqlSession session = factory.openSession();
//4.执行方法
List<User> userList = dao.findAll();
//遍历
for (User user:userList
) {
System.out.println(user);
}
//提交事务
session.commit();
//5.释放资源
session.close();
is.close();
}
}
**注:**更多配置信息,参考mybatis官网
三. Mybatis框架环境搭建详解
1. jar包目录介绍
ant : 可以用ant编译java类,生成class文件,ant可以把相关层架构成包
asm : java文件解析包 .spring依赖这个包
cglib : 动态代理包,使得mybatis不需要编写实现类<将接口与xml关联起来了>
comments-logging : 日志包,.spring依赖这个包
javassist : 字节码解析助手,处理class文件
log4j : 也是日志包
mybatis : 是mybatis的核心
mysql-connector : 是mysql的驱动
ognl : ognl表达式
slf4j : 日志包
... ...
2. 配置详情
2.1 全局配置文件
<configuration>
<!-- 配置环境-->
<environments default="development">
<!-- 配置mysql环境-->
<environment id="development">
<!-- 配置事务的类型-->
<transactionManager type="JDBC"/>
<!-- 配置数据源(连接池)-->
<dataSource type="POOLED">
<!-- 配置连接数据库的4个基本信息-->
< 标签内配置连接数据库的信息 >
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis_db"/>
<property name="username" value="root"/>
<property name="password" value="123"/>
</dataSource>
</environment>
</environments>
---- environments default=“development”:
default 配置当前所使用的的环境,值必须是的id值
可以有多个标签,声明可能使用的黄精,会被引用
---- transactionManager type=“JDBC”: 事务管理器类型
type属性可取值:
-
JDBC 底层事务与JDBC原有事务管理相同
-
MANAGED Mybatis不去管理事务,交给其他容器进行管理
---- dataSource type=“POOLED” :
POOLED : 使用连接池技术,访问频率比较高时使用.连接池的使用可以降低服务器的压力,提高连接对象重用性.
UNPOOLED : 不使用连接池技术.每次对数据库访问时打开数据库连接,访问结束后关闭数据库连接.
JNDI : java命名目录接口.数据库的连接可以依赖于其他技术活应用.
---- mapper:
resource = “cn/dao/UserDao.xml” 加载项目中的资源,目录寻找,中间是/
class=“cn.lmx.dao.UserDao”
url = “file:///E:/UserDao.xml” 加载互联网或读取本机的配置文件 >> file协议
---- package :
首先会找到包下的所有的[接口],然后去找和接口的名字相同的xml进行扫描<若没有接口,则无法扫描>
2.2 引入本地dtd
http://mybatis.org/dtd/mybatis-3-config.dtd 加载慢,是因为网慢,因为每次都需要联网请求dtd【如果自身网路比较顺畅可以不考虑】
解决方法 : 引入本地DTD文件
步骤:
1.下载对应的DTD : 直接复制链接在网络下载即可
2.打开setting>>Languages&Frameworks>>Schemas and DTDs
3.引入本地DTD文件
四. Mybatis框架搭建优化
1.配置别名
给指定的实体类起别名:
<!--使用typeAliases配置别名, 它只能配置pojo中类的别名
type: 实体类的全限定类名
alias: 指定别名,当指定别名之后可以忽略大小
-->
<typeAliases>
<typeAlias type="cn.pojo.User" alias="User"></typeAlias>
</typeAliases>
包下得所有类起别名明 : 别名就是当前类的名称 首字母小写(忽略大小写)
eg: 在cn.pojo 下得实体类User的别名就是user
<!--name : 包名 -->
<typeAliases>
<package name="cn.pojo"></package>
</typeAliases>
2. 引入properties配置文件
1.Mybatis也是支持属性文件的读取的
2.可以让代码的结构更加清晰
注意:configuration报错 >> 可能是标签书写顺序不对,这里报错不会影响编译结果的
jdbc.properties文件
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql:///mybatis_db
username=root
password=123
<!-- 配置properties 配置数据库的连接信息
可以在标签内配置连接数据库的信息,也可以通过属性引入外部信息配置文件信息
resource属性:
指定配置文件的位置,必须写在类路径下
resource 用来引入外部的配置文件
-->
<!--1.标签内配置连接数据库的信息-->
<!--<properties>
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306:/mybatis_db"/>
<property name="username" value="root"/>
<property name="password" value="123"/>
</properties>-->
<!--2.通过属性引入外部信息配置文件信息-->
<properties resource="jdbc.properties" ></properties>
3. 配置settings开启log4j支持
3.1 日志文件的作用
- 记录错误的信息到文件中
- 有日志级别方便查看
3.2 log4j的五种级别
- FATAL 严重错误
- ERROR 错误
- WARN 警告
- INFO 普通信息
- DEBUG 调试信息
注:只会显示当前级别及以上的信息
3.3 开启log4j支持
先导入log4j文件,在进行相关配置
<!--配置参数-->
<settings>
<!--控制台输出SQL-->
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
五. Mybatis的三种查询方式
位置:在创建dao接口的代理对象处
查询方式1 : sqlSession.selectList()
sqlSession.selectList() : 适合于结果集返回的是多条数据的时候 >> 返回一个结果集
eg:sqlSession.selectList(“cn.dao.UserDao.finAll”)
public void init() throws IOException {
//1.加载/读取配置文件
is = Resources.getResourceAsStream("SqlConfig.xml");
//2.创建工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(is);
//3.使用工厂生产对象
sqlSession = factory.openSession();
//4.执行方法 >> 这里的UserDao 是xml文件
List<User> userList = sqlSession.selectList("cn.dao.UserDao.finAll");
//遍历
for (User user:userList
) {
System.out.println(user);
}
//提交事务
session.commit();
//5.释放资源
session.close();
is.close();
查询方式2 : sqlSession.selectOne
sqlSession.selectOne : 适用于最多返回是一条结果集数据 >> 返回一个对象
查询方式3 : sqlSession.selectMap()
**sqlSession.selectMap() : 返回一个Map集合 **
**作用:**希望可以通过数据库中的某一列快速的找到这一列对应的结果集 >> eg : map.get(3)
eg:sqlSession.selectMap(“cn.dao.UserDao.findAll”,“id”)
>>(“xml文件全类名.调用的方法” ,“列名(希望数据库的哪一列作用的key)”)
注 : 在map.get()时,不要强转
六. 参数传递操作
参数传递1 : 单个参数
用 #{param1}接收参数 >> select * from user where id=#{param1}
参数传递2 : 传入对象
用#{id},#{name}…来接收参数 >> select * from user where id=#{id} and name=#{name}
参数传递3 : Map集合
用#{a},#{b}…来接收参数 >> select * from user where id=#{a} and name=#{b} (注:a,b为map集合的键)
*除了用#还可以使用$,但是建议用# :
# : 底层是使用占位符 ?
$ : 底层使用的是字符串的拼接 >> 在传的参数为字符串时,要用单引号将字符串引起来
七. mybatis中基于sqlSession的CRUD
pojo实体类:User
package cn.pojo;
/**
* 实体类
*/
import java.util.Date;
public class User {
private int id;//编号
private String name;//姓名
private String address;//地址
private String sex;//性别
private Date birthday;//生日
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", address='" + address + '\'' +
", sex='" + sex + '\'' +
", birthday=" + birthday +
'}';
}
}
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="cn.dao.UserDao"> //namespace可以为任意值,只有使用Mapper代理时,才会有特定写法(接口全类名)
<!-- 查询所有用户信息-->
<!-- id的名称就是sqlSession调用的方法名-->
<select id="findAll" resultType="cn.pojo.User">
select * from user1
</select>
<!--增加用户信息-->
<insert id="addUser" parameterType="cn.pojo.User">
insert into user1 values (#{user.id},#{user.name},#{user.address},#{user.sex},#{user.birthday})
</insert>
<!--删除用户信息-->
<delete id="delUser" parameterType="cn.pojo.User">
delete from user1 where id=#{user.id}
</delete>
<!--修改用户信息-->
<update id="updateUser" parameterType="cn.pojo.User">
update user1 set name=#{user.name} , address=#{user.address} , sex=#{user.sex} where id=#{user.id}
</update>
</mapper>
UserTest
package test;
import cn.dao.UserDao;
import cn.pojo.QueryUser;
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 cn.pojo.User;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;
public class UserTest {
private InputStream is;
private SqlSession session;
private UserDao dao;
@Before
public void init() throws IOException {
//1.加载/读取配置文件
is = Resources.getResourceAsStream("SqlConfig.xml");
//2.创建工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(is);
//3.使用工厂生产对象
session = factory.openSession();
}
@After
public void close() throws IOException {
//提交事务 >> 只有提交了事务,数据才会保存到硬盘中
/* 增删改操作写好后必须提交事务
提交事务方式 :
1.commit()手动提交
2.openSession(true)自动提交
*/
session.commit();
//6.释放资源
session.close();
is.close();
}
/**
* 查询所有信息
* @throws IOException
*/
@Test
public void testUser() throws IOException {
//5.使用代理对象dao执行方法
List<User> userList = session.selectOne("cn.dao.UserDao.findAll");
//遍历
for (User user:userList
) {
System.out.println(user);
}
}
/**
* 模糊查询
*/
@Test
public void unclearFindTest(){
List<User> users =session.selectOne("cn.dao.UserDao. ** ");
}
/**
* 增加用户信息
*/
@Test
public void addUserTest() throws IOException {
QueryUser queryUser = new QueryUser();
User user = new User();
user.setName("三藏");
user.setAddress("东土大唐");
user.setSex("男");
user.setBirthday(new Date());
int i = session.insert("cn.dao.UserDao.addUser",user);
}
/**
* 删除用户信息
*/
@Test
public void delUserTest(){
User user = new User();
user.setId(101);
int i = session.delete("cn.dao.UserDao.delUser",user);
}
/**
* 修改用户信息
*/
@Test
public void updateUserTest(){
User user = new User();
user.setId(2);
user.setName("憨憨");
user.setAddress("西天");
user.setSex("男");
int i = session.update("cn.dao.UserDao.updateUser",user);
}
}
注 : 参数类型可以省略,它会根据接收的类型自动判断.
八. Mybatis中基于Mapper代理方式的CRUD
1.Mapper 的动态代理作用
目前使用SQLSession进行CRUD的缺点:
1.没有办法实现多参数的传递
2.书写的时候没有借口,后期的维护就比较的低
解决方案: Mapper动态代理方式,实现CURD
2.示意图
3. 代码演示
SqlConfig.xml
<!-- 指定映射文件的位置,进行扫描-->
<mappers>
<mapper resource="cn/dao/UserDao.xml"></mapper>
</mappers>
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">
<!--namespace : 必须是接口所在的全路径-->
<mapper namespace="cn.dao.UserDao">
<!--id : id的名称和接口的名称必须保持一致-->
<!-- 查询所有用户信息-->
<select id="findAll" resultType="cn.pojo.User">
select * from user1
</select>
</mapper>
UserDao 接口:
import cn.pojo.User;
import java.util.List;
public interface UserDao {
/**
* 查询数据库所有信息
*/
List<User> findAll();
}
UserTest:
/**
* 查询所有信息
* @throws IOException
*/
@Test
public void testUser() throws IOException {
//1.加载/读取配置文件
InputStream is = Resources.getResourceAsStream("SqlConfig.xml");
//2.创建工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(is);
//3.使用工厂生产对象
SqlSession session = factory.openSession();
//4.创建dao接口的代理对象
UserDao dao = session.getMapper(UserDao.class);
//5.使用代理对象dao执行方法
List<User> userList = dao.findAll();
//遍历
for (User user:userList
) {
System.out.println(user);
}
//提交事务
session.commit();
//6.释放资源
session.close();
is.close();
}
4. 好处
1 .可以面向接口进行开发
2.可以传多个参数了
public void testUser() throws IOException {
//1.加载/读取配置文件
InputStream is = Resources.getResourceAsStream("SqlConfig.xml");
//2.创建工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(is);
//3.使用工厂生产对象
SqlSession session = factory.openSession();
//4.创建dao接口的代理对象
UserDao dao = session.getMapper(UserDao.class);
//5.使用代理对象dao执行方法
List<User> userList = dao.findAll();
//遍历
for (User user:userList
) {
System.out.println(user);
}
//提交事务
session.commit();
//6.释放资源
session.close();
is.close();
}
4.好处
- 可以面向接口进行开发
- 可以传多个参数了