Mybatis 上篇
一、什么是Mybatis:
MyBatis一个 是优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
持久化:持久化是将程序数据在持久状态和瞬时状态间转换的机制。即把数据保存到可永久保存的存储设备中
持久化的主要是将内存中的对象存储在数据库中,存储在磁盘文件中等等。
比如:在生活中 : 将鲜肉冷藏,吃的时候再解冻的方法等等
为什么需要持久化服务呢?
那是由于内存本身的缺陷引起的
内存断电后数据会丢失,比如银行账号等,
内存过于昂贵,需要持久化来缓存到外存。
二、Mybatis特点:
简单易学、
灵活,便于统一管理和优化、
解除sql与程序代码的耦合,提高了可维护性、
提供映射标签,支持对象与数据库的orm字段关系映射、
提供对象关系映射标签,支持对象关系组建维护、
提供xml标签,支持编写动态sql。
三、Mybatis实现流程:
1、加载配置并初始化:
触发条件:加载配置文件
处理过程:将SQL的配置信息加载成为一个个MappedStatement对象(包括了传入参数映射配置、执行的SQL语句、结果映射配置),存储在内存中。
2、接收调用请求:
触发条件:调用Mybatis提供的API
传入参数:为SQL的ID和传入参数对象
处理过程:将请求传递给下层的请求处理层进行处理。
3、处理操作请求:
触发条件:API接口层传递请求过来
传入参数:为SQL的ID和传入参数对象
处理过程:
a、根据SQL的ID查找对应的MappedStatement对象。
b、根据传入参数对象解析MappedStatement对象,得到最终要执行的SQL和执行传入参数。
c、获取数据库连接,根据得到的最终SQL语句和执行传入参数到数据库执行,并得到执行结果。
d、根据MappedStatement对象中的结果映射配置对得到的执行结果进行转换处理,并得到最终的处理结果。
e、释放连接资源。
4、返回处理结果将最终的处理结果返回。
四、第一个Mybatis:(其中的一些代码可以参考Mybatis官网:https://mybatis.org/mybatis-3/zh/getting-started.html)
1、创建一个Mave父工程为Mybatis,删除父工程中的src文件,父工程的pom文件用于添加项目中所需要的依赖,其次再创建一个Module子工程为01-mybatis:
2、在父工程的pom.xml中添加mysql、mybatis、junit依赖:
junit junit 4.11 test mysql mysql-connector-java 5.1.35 org.mybatis mybatis 3.5.6
3、在mysql中创建数据库,创建表,添加数据:
CREATE DATABASE Student; //创建数据库Student USE Student; //使用数据库 CREATE TABLE users( //向users表中设置id,name,age,grade等字段 id INT(10) NOT NULL PRIMARY KEY, NAME VARCHAR(15) NOT NULL, age INT(5) NOT NULL, grade VARCHAR(15) NOT NULL )ENGINE= INNODB; //engine=innodb ==>是数据库的数据引擎,数据库的引擎有两种:一种是InnoDB,它支持事务处理,另一种是MyISAM,它的执行熟读快,不支持事务处理。 INSERT INTO users VALUES(1,"张三",18,80); INSERT INTO users VALUES(2,"李章",20,70); INSERT INTO users VALUES(3,"王二",19,60); INSERT INTO users VALUES(4,"李四",18,85); INSERT INTO users VALUES(5,"赵三",16,90); SELECT * FROM users;
4、在项目的resources中创建一个mapper文件夹,其次在创建一个配置mybatis-config的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">
default="development">
5、在项目中创建一个pojo文件夹,创建一个User.java的实体类
package com.zy.pojo; public class User { private int id; private String name; private int age; private String grade; public User() { } public User(int id, String namae, int age, String grade) { this.id = id; this.name = namae; this.age = age; this.grade = grade; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getNamae() { return name; } public void setNamae(String namae) { this.name = namae; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getGrade() { return grade; } public void setGrade(String grade) { this.grade = grade; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + ", grade='" + grade + '\'' + '}'; } }
6、在项目中创建一个dao文件夹,创建一个UserDao.java的接口类:
package com.zy.dao; import com.zy.pojo.User; import java.util.List; public interface UserDao { ListgetStudent();
7、在项目的resources中创建一个mapper文件夹,其次在创建一个配置Usermapper的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">
8、在项目中创建一个util文件夹,创建一个UserUtil.java的工具类 :
package com.zy.util; 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 java.io.IOException; import java.io.InputStream; public class UserUtil { private static SqlSessionFactory sqlSessionFactory; static { try { String resource = "mapper/Mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory= new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { e.printStackTrace(); } } public static SqlSession getSqlSession() { SqlSession sqlSession = sqlSessionFactory.openSession(); return sqlSession; } }
9、在项目的test下的java文件里面创建一个项目test的java文件:
package com.zy.dao; import com.zy.pojo.User; import com.zy.util.UserUtil; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.List; public class MybatisTest { @Test public void test(){ SqlSession sqlSession = UserUtil.getSqlSession(); UserDao userDao = sqlSession.getMapper(UserDao.class); Liststudent = userDao.getStudent(); for (User user : student) { System.out.println(user); } sqlSession.close(); }
10、程序运行结果:
五、增删改查(这是我重写创建的mave项目,但其中的代码换汤不换药)
操作步骤:1、编写对数据库操作的接口
2、编写接口对应的mapper文件的sql语句
3、在Test类java文件中编写对sql语句的实现和运行。
注意:增删改需要事务提交,如果不事务提交的话,数据表中的数据是没有什么改变的
import com.zy.pojo.User; import java.util.List; public interface UserDao { //查询全部用户信息 ListgetUserList(); //根据id查询信息 User getUserById(int id); //新增数据 int addUser(User user); //删出数据 int deleteUser(int id); //改数据 int updateUser(User user); }
<?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">
insert into Myuser(id,name,age) values (#{id},#{name},#{age});
delete from Myuser where id=#{id};
update Myuser set name =#{name},age=#{age} where id=#{id};
package com.zy.dao; import com.zy.pojo.User; import com.zy.utils.userutils; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.List; public class UserTest { @Test public void test(){ //获取sqlseeion对象 SqlSession sqlSession= userutils.getSqlSession(); //执行sql语句 UserDao userDao = sqlSession.getMapper(UserDao.class); ListuserList = userDao.getUserList(); for (User user : userList) { System.out.println(user); } sqlSession.close(); } @Test public void getUserById(){ SqlSession sqlSession= userutils.getSqlSession(); UserDao userDao = sqlSession.getMapper(UserDao.class); User id = userDao.getUserById(10); System.out.println(id); sqlSession.close(); } @Test /*增删改都要提交事务*/ public void addUser(){ SqlSession sqlSession= userutils.getSqlSession(); UserDao userDao = sqlSession.getMapper(UserDao.class); int result = userDao.addUser(new User(1, "赵四", 20)); if (result>0) { System.out.println("插入成功"); } sqlSession.commit();//提交事务,如果不提交事务,则插入的数据不会更新到数据库中 sqlSession.close(); } @Test public void updateUser(){ SqlSession sqlSession = userutils.getSqlSession(); UserDao mapper = sqlSession.getMapper(UserDao.class); int user = mapper.updateUser(new User(20, "王二", 62)); if (user>0) { System.out.println("插入成功"); } sqlSession.commit(); sqlSession.close(); } @Test public void deleteUser(){ SqlSession sqlSession= userutils.getSqlSession(); UserDao userDao = sqlSession.getMapper(UserDao.class); userDao.deleteUser(30); sqlSession.commit(); sqlSession.close(); } }
六、Map
1、假设,实体类或者数据库中的表,字段或者参数过多,应当考虑使用Map
//使用map int addUser2(Mapmap);
insert into Myuser(id,name,age) values (#{userid},#{userName},#{age});
//使用map @Test public void addUserw2(){ SqlSession sqlSession = userutils.getSqlSession(); UserDao mapper = sqlSession.getMapper(UserDao.class); HashMapmap = new HashMap (); map.put("userid",6); map.put("username","李四"); map.put("userword",53); mapper.addUser2(map); sqlSession.close(); }
Map传递参数,直接在sql中取出key即可
parameterType="map"
对象传递参数,直接在sql中取对象的属性即可
parameterType="object"
只有一个基本类型的情况下,可以直接在sql中取到!
多个参数使用map,或者注解
2、模糊查询怎么写?
a、java代码执行的时候,传递通配符 % %
ListuserList = userDao.getUserList("%李%"); for (User user : userList) { System.out.println(user); }
b、在sql拼接中使用通配符
select * from Myuser where name like "%"#{value}"%";
七、配置解析:
1、核心配置文件
2、环境配置(environments)
MyBatis 可以配置成适应多种环境,不过要记住:尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。
mybatis默认的事务管理器是JDBC、连接池:POOLED
3、属性(properties)
可以通过属性来实现引用配置文件
可以在外部进行配置,并可以进行动态替换。
既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素来传递。(如:db.properties)
编写一个配置文件:db.proerties
driver=com.mysql.cj.jdbc.Driver url=jdbc:mysql://localhost:3306/Mybatis?useSSL=true&userUnicode=true&characterEncode=Utf-8 username=root password=123456
1、在核心配置文件中引入
<configuration> <properties resource="db.properties"/> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> dataSource> environment> environments> <mappers> <mapper resource="mapper\UserMapper.xml"/> mappers>
2、也可以在其中直接引用(只增加一些属性配置)
<properties resource="db.properties"> <property name="username" value="root"/> <property name="password" value="123456"/> properties>
注意:如果两个文件有同一个字段,优先使用外部配置文件
八、类型别名(typeAliases)
1、类型别名可为 Java 类型设置一个缩写名字。仅用于 XML 配置,意在降低冗余的全限定类名书写
<typeAliases>
<typeAlias type="com.zy.pojo.User" alias="User"/>
typeAliases>
2、也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,
扫描实体类的包,它的默认别名就是为这个类名,首字母小写
<typeAliases>
<package name="com.zy.pojo"/>
typeAliases>
注意:在实体类比较少的时候,使用第一种方式;实体类比较多的时候,使建议使用第二种。它们的区别在于:第一种可以自定义别名,第二种不可以自定义别名,如果非要使用别名,只用使用注解@Alias()
九、映射器(mappers)
第一种方式:使用resource绑定注册
第二种方式:使用class文件绑定注册接口
class="com.zy.dao.UserDao">
注意:
接口和它的mapper配置文件必须同名,
接口和它的接口配置文件必须在给你一个包下
第三种方式:使用扫描包进行注入绑定
十、resultMap使用
resultMap结果集用于解决属性名和字段名不一致
如:
数据库中的属性值为:id 、name 、password
我们写的实体类为:id 、name 、pwd
如果没有及时发现,我们查询的sql语句运行结果可能为null,因此我们使用resultMap结果集。
<resultMap id="UserMap" type="User">
<result column="id" property="id">result>
<result column="name" property="name">result>
<result column="age" property="agee">result>
resultMap>
<select id="getUserById" resultMap="UserMap">
select * from Myuser where id=#{id};
select>
十一、分页(Limit)
1、语法:select * from 表名 limit startindex,pagesize;
SELECT * FROM myuser LIMIT 1,2;
2、在mybatis中实现分页
第一、创建实体类
第二、创建接口类
第三、创建Mapp.xml
第四、创建工具类
第五、Test类
package com.zy.pojo;
public class User {
private int id;
private String name;
private int age;
public User() {
}
public User(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
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 int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + '}'; } }
package com.zy.dao;
import com.zy.pojo.User;
import java.util.List;
import java.util.Map;
public interface UserDao {
//根据id查询信息
User getUserById(int id);
//分页
List getUserByLimit(Map map);
}
<?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.zy.dao.UserDao">
<select id="getUserById" resultType="com.zy.pojo.User">
select * from Myuser where id=#{id};
select>
<select id="getUserByLimit" parameterType="map" resultType="com.zy.pojo.User" >
select * from Myuser limit #{startIndex},#{pageSize};
select>
mapper>
package com.zy.utils;
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 java.io.IOException;
import java.io.InputStream;
//工具类
//sqlsessionFactory -->sqlSession
public class userutils {
private static SqlSessionFactory sqlSessionFactory;
static {
try {
//使用mybatis第一步:获取使用sqlsessionFactory对象
String resource ="mapper/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
/*既然有了 SqlSessionFactory,
顾名思义,我们可以从中获得 SqlSession 的实例。SqlSession
提供了在数据库执行 SQL 命令所需的所有方法。*/
public static SqlSession getSqlSession(){
SqlSession sqlSession = sqlSessionFactory.openSession();
return sqlSession;
}
}
package com.zy.dao;
import com.zy.pojo.User;
import com.zy.utils.userutils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.HashMap;
import java.util.List;
public class UserTest {
@Test
public void getUserById(){
//获取sqlseeion对象
SqlSession sqlSession= userutils.getSqlSession();
//执行sql语句
UserDao userDao = sqlSession.getMapper(UserDao.class);
User userById = userDao.getUserById(5);
System.out.println(userById);
}
@Test
public void getUserByLimit() {
SqlSession sqlSession = userutils.getSqlSession();
UserDao mapper = sqlSession.getMapper(UserDao.class);
HashMap hashMap = new HashMap();
hashMap.put("startIndex",1);
hashMap.put("pageSize",2);
List userByLimit = mapper.getUserByLimit(hashMap);
for (User user : userByLimit) {
System.out.println(user);
}
}
}
十二、注解开发 (简单查询可以使用注解,但遇到复杂的查询还是使用xml)
本质:反射机制实现
底层:动态代理
1、在接口上实现,
public interface UserDao {
//使用注解
@Select("select * from myuser")
List getUsers();
}
2、需要在核心配置文件中绑定接口
<mappers>
<mapper class="com.zy.dao.UserDao">mapper>
mappers>
3、测试
public class UserDaoTest {
@Test
public void test1() {
SqlSession sqlSession = userutils.getSqlSession();
//底层主要应用反射
UserDao mapper = sqlSession.getMapper(UserDao.class);
List users = mapper.getUsers();
for (User user : users) {
System.out.println(user);
}
sqlSession.close();
}
}
4、CRUD
1、可以在工具类创建的时候实现事务自动提交
public static SqlSession getSqlSession(){
//设置事务自动提交
return sqlSessionFactory.openSession(true);
}
注意:必须将接口注册绑定到我们的核心配置文件中
2、增删改查接口
public interface UserDao {
//使用注解
@Select("select * from myuser")
List getUsers();
//@Param :方法存在多个参数,所有参数必须加上@Param
//User getUserByid(@Param("id") int id,@Param("name") String name);
@Select("select * from Myuser where id=#{id}")
User getUserByid(@Param("id") int id);
@Insert("insert into Myuser(id,name,age)values(#{id},#{name},#{age})")
int addUser(User user);
@Update("update Myuser set name=#{name},age=#{age} where id=#{id}")
int updateUser (User user);
/*基本类型就用 @param
* @Param("uid")
* int id
* 以 @Param("uid") 中的uid为准 */
@Delete("delete from Myuser where id=#{uid}")
int deleteUser(@Param("uid") int id);
}
3、测试(注意:必须将接口注册绑定到我们的核心配置文件中)
public class MybatisTest {
@Test
public void test1() {
SqlSession sqlSession = userutils.getSqlSession();
//底层主要应用反射
UserDao mapper = sqlSession.getMapper(UserDao.class);
List users = mapper.getUsers();
for (User user : users) {
System.out.println(user);
}
sqlSession.close();
}
@Test
public void getUserById(){
SqlSession sqlSession = userutils.getSqlSession();
UserDao mapper = sqlSession.getMapper(UserDao.class);
User byid = mapper.getUserByid(1);
System.out.println(byid);
sqlSession.close();
}
@Test
public void addUser(){
SqlSession sqlSession = userutils.getSqlSession();
UserDao mapper = sqlSession.getMapper(UserDao.class);
mapper.addUser(new User(2,"张三",30));
sqlSession.close();
}
@Test
public void updateUser(){
SqlSession sqlSession = userutils.getSqlSession();
UserDao mapper = sqlSession.getMapper(UserDao.class);
mapper.updateUser(new User(2,"王家",30));
sqlSession.close();
}
@Test
public void deleteUser(){
SqlSession sqlSession = userutils.getSqlSession();
UserDao mapper = sqlSession.getMapper(UserDao.class);
mapper.deleteUser(1);
sqlSession.close();
}
}
关于 @Param()注解:
基本类型的参数或者string类型,需要加上
引用类型不需要加上
如果只有一个基本类型的话,可以忽略,但建议加上
在sql中引用的就是我们这里的@Param(“ ”) 设定的属性名
拓展:lombok使用
@Data //动态添加get/set/tostring/equals等方法
@AllArgsConstructor //添加构造方法
@NoArgsConstructor // 添加无参构造
@Accessors(chain = true) //引入链式加载方法
1、在IDEA中安装Lombok插件
2、在项目中导入lombok的jar包
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.18.16version>
dependency>
dependencies>
3、在实体类上加上注解(就可以省略不写Constructor、set、get等)
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private int id;
private String name;
private int age;
}