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依赖:
<dependencies> <!-- 添加junit依赖--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <dependency> <!-- 添加mybatis依赖--> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.35</version> </dependency> <dependency> <!-- 添加mybatis依赖--> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.6</version> </dependency> </dependencies>
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"> <configuration> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/Student?useSSL=true&userUnicode=true&characterEncode=Utf-8"/> <property name="username" value="root"/> <property name="password" value="123456"/> </dataSource> </environment> </environments> <mappers> <mapper resource="mapper/Usermapper.xml"/> </mappers> </configuration>
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 { List<User> getStudent();
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"> <mapper namespace="com.zy.dao.UserDao"> <select id="getStudent" resultType="com.zy.pojo.User"> select * from users; </select> </mapper>
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); List<User> student = 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 { //查询全部用户信息 List<User> getUserList(); //根据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"> <mapper namespace="com.zy.dao.UserDao"> <select id="getUserList" resultType="com.zy.pojo.User"> select * from Myuser; </select> <select id="getUserById" resultType="com.zy.pojo.User" parameterType="int"> select * from Myuser where id=#{id}; </select> <insert id="addUser" parameterType="com.zy.pojo.User"> insert into Myuser(id,name,age) values (#{id},#{name},#{age}); </insert> <delete id="deleteUser" parameterType="int"> delete from Myuser where id=#{id}; </delete> <update id="updateUser" parameterType="com.zy.pojo.User"> update Myuser set name =#{name},age=#{age} where id=#{id}; </update> </mapper>
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); List<User> userList = 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(Map<String,Object> map);
<!-- 使用map 传递map的key--> <insert id="addUser2" parameterType="map"> insert into Myuser(id,name,age) values (#{userid},#{userName},#{age}); </insert>
//使用map @Test public void addUserw2(){ SqlSession sqlSession = userutils.getSqlSession(); UserDao mapper = sqlSession.getMapper(UserDao.class); HashMap<String, Object> map = new HashMap<String, Object>(); 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代码执行的时候,传递通配符 % %
List<User> userList = userDao.getUserList("%李%"); for (User user : userList) { System.out.println(user); }
b、在sql拼接中使用通配符
select * from Myuser where name like "%"#{value}"%";
七、配置解析:
1、核心配置文件
<!--核心配置文件-->
<configuration>
<!--<environments default="development">-->
<environments default="test">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/Mybatis?useSSL=true&userUnicode=true&characterEncode=Utf-8"/>
<property name="username" value="root"/>
<property name="password" value='123456'/>
</dataSource>
</environment>
<mappers>
<mapper resource="mapper\UserMapper.xml"/>
</mappers>
</configuration>
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配置文件--> <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>
<select id="getUserList" resultType="User"> select * from Myuser; </select>
2、也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,
扫描实体类的包,它的默认别名就是为这个类名,首字母小写
<!--可以给实体类起别名--> <typeAliases> <!--<typeAlias type="com.zy.pojo.User" alias="User"/>--> <package name="com.zy.pojo"/> </typeAliases>
<select id="getUserList" resultType="user"> select * from Myuser; </select>
注意:在实体类比较少的时候,使用第一种方式;实体类比较多的时候,使建议使用第二种。它们的区别在于:第一种可以自定义别名,第二种不可以自定义别名,如果非要使用别名,只用使用注解@Alias()
九、映射器(mappers)
第一种方式:使用resource绑定注册
<!--每一个Mapper.xml都需要在mybatis核心配置文件中注册!--> <mappers> <mapper resource="mapper/UserMapper.xml"/> </mappers>
第二种方式:使用class文件绑定注册接口
<!--绑定接口-->
<mappers>
<mapper class="com.zy.dao.UserDao"></mapper>
</mappers>
注意:
接口和它的mapper配置文件必须同名,
接口和它的接口配置文件必须在给你一个包下
第三种方式:使用扫描包进行注入绑定
<!--绑定接口--> <mappers> <package name="com.zy.dao/> </mappers>
十、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<User> getUserByLimit(Map<String,Integer> 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<String, Integer> hashMap = new HashMap<String, Integer>(); hashMap.put("startIndex",1); hashMap.put("pageSize",2); List<User> userByLimit = mapper.getUserByLimit(hashMap); for (User user : userByLimit) { System.out.println(user); } } }
十二、注解开发 (简单查询可以使用注解,但遇到复杂的查询还是使用xml)
本质:反射机制实现
底层:动态代理
1、在接口上实现,
public interface UserDao { //使用注解 @Select("select * from myuser") List<User> 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<User> 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<User> 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<User> 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.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.16</version> </dependency> </dependencies>
3、在实体类上加上注解(就可以省略不写Constructor、set、get等)
@Data @AllArgsConstructor @NoArgsConstructor public class User { private int id; private String name; private int age; }