MyBatis
什么是Mybatis
-
MyBatist是一款优秀的持久层框架
-
他支持定制化SQL,存储过程以及高级映射
-
MyBatis避免几乎所有的JDBC代码和手动设置参数以及获取结果集
-
MyBatis原名叫iBatis
-
2013年11月迁入github,所以现在要去giehub上找该开源项目的源码
-
iBatis提供的持久层框架包括SQL Maps和Data Access Objects(DAOs)
什么是持久化
说白了就是将数据存放到数据库中,使数据持久化,要是数据在内存中根本不符合数据持久化的概念
- 持久化就是将程序的数据在持久状态和瞬时状态转化的过
- 使数据达到持久化状态的不仅仅是数据库(JDBC),还可以使用I/O
什么是持久层
在一个完整的企业级开发环境中,注重的是分工明确,逻辑分化,不同层实现不同的业务
之前学习了MVC三层架构,分别对应module层,view层,controler层
- 应用数据数据持久化技术的层,数据持久化存在的代码块
- 在项目中分层名称为:Data Access Objects(DAOs)
MyBatis的优点
相对于JDBC而言,的确还是有很多好处的,最重要的一点:技术没有高低
-
简单易学
-
灵活:实现SQL和程序代码分离,当然如果不使用MyBatis也可以实现,目前能想到的手段就是写在配置文件(propies)中,
MyBatis是将SQL写在xml中,便于统一管理和优化。
-
解除SQL与程序代码的耦合,将持久化的代码块以独立分层的方式写在DAO层,将业务逻辑和数据访问逻辑分离,使系统设计更清晰,也提高了可维护性。
-
提供映射标签,支持对象与数据库的ORM字段关系映射
-
提供对象关系映射标签,支持对象关系组建维护
-
提供XML标签,支持编写动态SQL
使用MyBatis
-
编写MyBatis配置文件
配置文件放在src/resources资源目录下**(给我记住一句话,这句话到哪里都适用,“约定大于配置”)**
<configuration> <enviroments default="development"> <environment id="development"> <transationManager 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> </enviroments> <mappers> <!--每一个Mapper.xml都需要在Mybatis的配置文件中注册,个JavaWeb中的每一个Servlet都需要在web.xml中注册是一个道理--> <!--仔细看是外层大标签是mappers,所以可以注册多个--> <!--不同包级之间一定要使用 "/" 分割,否则出错了别来找我哦!--> <mapper resource="..." /> <mapper resourc="..." /> </mappers> </configuration>
-
获取SQLSessionFactory对象(可以封装为工具类,固定代码使用)
String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
-
创建一个能执行SQL的对象
//该对象与connetion对象无异,其旗下的方法是直接可以执行SQL语句的 SqlSession sqlssion = sqlSessionFactory.openSession();
编写代码阶段
-
DAO层
//编写DAO层接口 public interface UserDao{ //User对象为数据库的实体类 List<User> geUserList(); }
-
接口实现类有原来的UserDaoImp转变成一个Mapper配置文件
在使用JDBC的时候UserDaoImpl做为操作数据库的对象,完成对数据库中User的查询,更新,删除,查找操作。
现在,Mybatis中出现了Mapper名称,XML格式的配置文件来代替原来使用JDBC完成操作代码。
//等待编写
测试阶段
重点且致命性错误(一)
org.apache.ibatis.binding.BindingException: Type interface com.kuang.dao.UserDao is not known to the MapperRegistry. 英文释义:registry——>登记处 //报该错误是因为,每一个Mapper.XML都需要在Mybatis核心配置文件中注册
重点且致命性错误(二)
//错误示意:初始化异常失败 java.lang.ExceptionInInitializerError //报该错误是因为Maven的原因,还是上面提到的一句话——————>“约定大于配置”
//调用响应方法获取SQL执行对象————>SqlSession SqlSession sqlsession = MyBatisUtil.getSqlSession(); //UserDao是数据库操作的接口,面向接口编程,直接获取该接口[详询DAO层配置] UserDao userdao = sqlsession.getMapper(UserDao.class); //调用该接口的方法 List<User> list = userdao.getUserList();
CRUD
likely that neither a Result Type nor a Result Map was specified.
可能既没有指定结果类型也没有指定结果映射。
Mybatis使用思路梳理
到这里,其实大家已经了解mybatis各个部件的功能了,接下来就是将上述这些操作进行有规则的组合起来,大家就能轻松愉悦的使用我们的持久化框架Mybatis了,接下来大家跟着我的思路走,理完一边操作思路再结合我的实例,就能达到无脑上手操作的水平啦。
1、创建一个Maven项目,且Pom.xml中导入以下依赖
<!-- 配置SQL链接对象-->
<!-- 注意mysql 5.1.47版本有问题,报错 Communications link failure-->
<!-- 报错误为通信链接失败-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
<!-- 配置Mybatis对象-->
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.9</version>
</dependency>
2、编写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">
<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/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!-- mybatis注册-->
<mappers>
<mapper resource="Mapper.xml"/>
</mapper
</configuration>
3、跟数据库连接,并根据数据库表中的字段编写响应的实体类
- 数据表名称ibatis,分别有 id , name , age三个字段
-
在Java中编写对应的实体类,一定要跟数据库中的字段名称和类型相对应
/** * 该类为对应数据的实体类 */ public class Users { private String id; private String name; private int age; public Users() { } public Users(String id, String name, int age) { this.id = id; this.name = name; this.age = age; } public String getId() { return id; } public void setId(String 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 "Users{" + "id='" + id + '\'' + ", name='" + name + '\'' + ", age='" + age + '\'' + '}'; } }
4、编写接口对象,并编写对数据库操作的方法
public interface UserDao {
//获取数据库表中的所有记录
List<Users> getUserList();
//根据ID查询表中记录
public List<Users> SearchUser(String ids);
//增加记录
public int addUser(Users user);
//删除记录
public int DelUser(String id);
//更新记录
public int UpdateUser(Users user);
}
5、编写书写SQL的xml文件,该文件集中书写SQL,实现了代码和SQL的分离(我的文件名叫:Mapper.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.darling.Dao.UserDao">
<!-- 查询表中的全部记录-->
<select id="getUserList" resultType="com.darling.Pojo.Users">
select * from ibatis
</select>
<!-- 向数据库表中插入数据,#{id} 是从传过来的对象中取数据-->
<insert id="addUser" parameterType="com.darling.Pojo.Users">
insert into ibatis (`id`,`name`,`age`)
values (#{id},#{name},#{age})
</insert>
</mapper>
6、编写测试类,键入下列代码(运行结果我就不贴了)
public static void ListAllUser(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
UserDao userDao = sqlSession.getMapper(UserDao.class);
//如果执行成功那么就返回ibatis表中的所有记录
List<Users> List = userDao.getUserList();
for (Users users : List) {
System.out.println(users);
}
}
//查询数据库表中的记录,以ID为条件
public static void SearchUser(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
UserDao mapper = sqlSession.getMapper(UserDao.class);
List<Users> users = mapper.SearchUser("3");
for (Users user : users) {
System.out.println(user);
}
sqlSession.close();
}
完成上述操作之后,基本上Mybatis就毕业了,但是还是有必要更深一步详细的详细解释一下,我们使用数据库做的最多的是什么?那必然是CRUD增删改查,有了上面的基本理解之后,接下来我就带着大家一步一步的解释这些参数上面的关键字都代表的是什么意思!
CRUD
向数据库中添加数据
-
在 UserDAO接口内编写约束方法
public interface UserDao { //增加记录 public int addUser(Users user); }
注意一点在形参中的参数为Users实体类的类型,下面会提到。
-
在我们编写的Mapper.xml中重点看以下代码
<mapper namespace="com.darling.Dao.UserDao"> <!-- 向数据库表中插入数据,#{id} 是从传过来的对象中取数据--> <insert id="addUser" parameterType="com.darling.Pojo.Users"> insert into ibatis (`id`,`name`,`age`) values (#{id},#{name},#{age}) </insert> </mapper>
到这里有很多关键字就需要解释一下了,首先是
-
namespace=“com.darling.Dao.UserDao”——>这个是将我们当前的Mapper跟我们编写的UserDao接口进行绑定
-
id=“addUser”——>这个ID里面填写的是我们接口中定义的方法
-
parameterType=“com.darling.Pojo.Users”——>注意这里面是我们接口中定义方法的形式参数的类型,如果是自己编写的类型必须是要从包级别一直引用到自己编写的返回值类型类。
-
#{id},#{name},#{age}——>首先这个是引用数据中参数,大家可以看到大括号中的名称跟我们编写的实体类Users中的属性是一致的,这里强调一下必须是一致的。
#{ }——>Mybatis中引用数据的常用方式,一定记住,后面还会用到,我就不提了。
-
-
编写测试方法,执行看结果即可
//实现添加用户的操作 public static void addUser(){ //获取sql操作对象,基本操作,日后封装成工具类 SqlSession sqlSession = MybatisUtil.getSqlSession(); UserDao mapper = sqlSession.getMapper(UserDao.class); int flag = mapper.addUser(new Users("5", "八重神子", 80)); System.out.println(flag); //向数据库提交数据,否者不会更改数据库表内容 sqlSession.commit(); //释放操作对象 sqlSession.close(); }
删除数据表中的记录
-
在 UserDAO接口内编写约束方法
public interface UserDao { //删除记录 public int DelUser(String id); }
注意在形参中参数类型和形参名称,下面会提到。
-
在我们编写的Mapper.xml中重点看以下代码
<!-- 删除表中记录--> <delete id="DelUser" parameterType="String" > delete from ibatis where id=#{id} </delete>
记住不用忘了标签一定要写在标签内。
注意这里的parameterType内写的是String类型。
注意#{id}引用数据的数据名称跟接口中定义的方法的形参名称相同,必须相同!!!
-
编写测试方法,执行看结果即可
//删除数据表中的记录 public static void DelUser(){ SqlSession sqlSession = MybatisUtil.getSqlSession(); UserDao mapper = sqlSession.getMapper(UserDao.class); //删除ID为2的记录 int i = mapper.DelUser("2"); if (i>0) { System.out.println("删除成功"); } //提交上述执行的事务,是数据库中的记录发生改变 sqlSession.commit(); sqlSession.close(); }
更新数据表中记录
-
在 UserDAO接口内编写约束方法
public interface UserDao { //更新记录 public int UpdateUser(Users user); }
注意在形参中参数类型和形参名称,下面会提到。
-
在我们编写的Mapper.xml中重点看以下代码
<!-- 更新记录--> <update id="UpdateUser" parameterType="com.darling.Pojo.Users"> update ibatis set name=#{name} where id=#{id} </update>
记住不用忘了标签一定要写在标签内。
-
编写测试方法,执行看结果即可
//更新数据库中的数据 public static void UpdateUser(){ SqlSession sqlSession = MybatisUtil.getSqlSession(); UserDao mapper = sqlSession.getMapper(UserDao.class); int flag = mapper.UpdateUser(new Users("5", "八重神子", 80)); if (flag>0) { System.out.println("数据更新成功"); } sqlSession.commit(); sqlSession.close(); }
查询数据表中的数据
这里我们使用ID匹配的方式来进行查询。
-
在 UserDAO接口内编写约束方法
public interface UserDao { //根据ID查询表中记录 public List<Users> SearchUser(String ids); }
-
在我们编写的Mapper.xml中重点看以下代码
<!-- 不管是参数的数据还是对象的数据都需要使用 #{}来引用--> <select id="SearchUser" parameterType="String" resultType="com.darling.Pojo.Users"> select * from ibatis where id=#{ids} </select>
记住不用忘了标签一定要写在标签内。
-
编写测试方法,执行看结果即可
//查询数据库表中的记录,以ID为条件 public static void SearchUser(){ SqlSession sqlSession = MybatisUtil.getSqlSession(); UserDao mapper = sqlSession.getMapper(UserDao.class); List<Users> users = mapper.SearchUser("3"); for (Users user : users) { System.out.println(user); } sqlSession.close(); }
总结
看到这里的话,你的Mybatis正常使用已经没有任何问题了,无非就是CRUD的操作嘛,多看两遍,自己练练手,这个持久化框架就已经被你拿下了,学习的时候体会一下Mybatis带来的便捷性,跟JDBC自己编写DAO层使用Java代码跟SQL代码结合来实现CRUD的操作相比对,Mybatis绝对是更加便捷啦,还是亘古不变的话——>懒惰变相的使人进步。
错误预判
博主在自己学习的时候发现了一个很有意思的bug,这里就跟大家分享一下,代码我贴在这里,相关的注释也有,有兴趣的自己尝试一下吧!!!(被注释掉的代码就是出现问题的代码,有兴趣的米娜桑自取…)
//更新数据库中的数据
/**
* 发现问题:
* 如果我们使用伪链式编程的思路来进行操作并需要更新数据库表中的数据的时候
* 我们就无法重写获取当初我们使用链式编程的操作sqlSession的对象了,这样就算从别处获得SqlSession对象来进行提交
* 那么也不会对数据库进行任何改变和数据更新
*/
public static void UpdateUser(){
// if (MybatisUtil.getSqlSession().getMapper(UserDao.class).UpdateUser(new Users("5","李超群",80))>0) {
// System.out.println("数据更新成功!");
// }
// MybatisUtil.getSqlSession().commit();
// MybatisUtil.getSqlSession().close();
}
}
时候发现了一个很有意思的bug,这里就跟大家分享一下,代码我贴在这里,相关的注释也有,有兴趣的自己尝试一下吧!!!(被注释掉的代码就是出现问题的代码,有兴趣的米娜桑自取…)
//更新数据库中的数据
/**
* 发现问题:
* 如果我们使用伪链式编程的思路来进行操作并需要更新数据库表中的数据的时候
* 我们就无法重写获取当初我们使用链式编程的操作sqlSession的对象了,这样就算从别处获得SqlSession对象来进行提交
* 那么也不会对数据库进行任何改变和数据更新
*/
public static void UpdateUser(){
// if (MybatisUtil.getSqlSession().getMapper(UserDao.class).UpdateUser(new Users("5","李超群",80))>0) {
// System.out.println("数据更新成功!");
// }
// MybatisUtil.getSqlSession().commit();
// MybatisUtil.getSqlSession().close();
}
}