在mybatis初次学习Mybatis的时候,遇到了很多问题,虽然阿里云的视频有教学,但是视频教学所使用的软件和我自己使用的软件不用,我自己用的数据库是oracle数据库,开发环境是idea。而且视频中只是将mybatis这一部分抽出来讲,实际上还需要一些知识储备,我本身是了解了oralce基本的操作后,再开始学习Mybatis的,过程可能会走很多弯路,和遇到很多不理解或者理解错误的地方,现在暂时只能囫囵吞枣,等有一定了解后,再回头看看,总结和更改我的一些认知。
Mybatis是什么?
mybatis是基于java持久层的框架,持久层就是把业务数据存储到硬盘,在断电或者重启系统后,仍然可以读取这些数据。就好像玩游戏需要保存进度一样,不然每次都需要重头开始玩。java互联网可以通过mybatis框架访问数据库。
没有Mybatis之前怎么访问数据库?
在早期,如果需要访问oracle数据库,需要专门写一个程序,如果访问mysql,又需要专门写一个程序,后来就有了jdbc(Java DataBase Connectivity,java数据库连接),jdbc是一种用来执行sql语句的java api,可以为多种数据库提供统一的访问。简单来说,它可以与数据库建立连接,发生操作数据库的语句,处理结果。但是jdbc的工作量也是很大的,而且很不好用,所以出现了ORM(Object relational Mapping,对象关系映射 ),我们把POJO对象和数据库表相互映射的框架称为ORM,mybatis和hibernate都是ORM框架,而且因为mybatis对jdbc的封装很好,而且很灵活,所以几乎可以完全取代jdbc。
Mybatis的优点
mybatis有三个优点:
- 不屏蔽SQL,这样可以更加精确定位SQL语句,可以对其进行优化和改造。
- 提供更强大灵活的映射机制。满足了经常变换的互联网应用的要求。
- 提供了使用Mapper的接口编程,简化了工作。
除了mybatis,还有其他框架,比如Hibernate,hibernate与mybatis同样是java持久层的框架,都可以通过注解或者xml提供映射规则。但是hibernate不需要编写SQL就可以通过映射关系去操作数据库,这样程序员不需要精通SQL,只需要操作POJO(Plain Ordinary Java Object,简单的java对象)就可以操作对应的数据库的表了,但是这也是缺点,当多表关联超过3个,hibernate的性能就会丢失,而mybatis可以自定义SQL,映射关系,所以,他比hibernate更加灵活。但是mybatis也有缺点,因为需要编写SQL和映射规则,所以工作量比hibernate多。所以如果系统对性能要求不高时,可以实用hibernate,如果对性能要求高可以使用mybatis。
Mybatis的核心组件
首先先了解mybatis的核心组件有哪些,然后再去了解这些组件的作用和实现原理。mybatis的核心组件分为4个部分:
- SqlSessionFactoryBuilder(构造器)——它会根据配置或者代码生成SqlSessionFactory。
- SqlSessionFactory(工厂接口)——用来生成SqlSession。
- SqlSession(会话)——既可以发送SQl并执行返回结果,也可以获取Mapper的接口。
- SQL Mapper(映射器)——MyBatis新设计存在的组件,由一个java接口和XML文件(或者注解)构成。需要给出对应的SQL和映射规则。负责发送SQL,并返回结果。
Mybatis的配置
开始配置之前,需要准备Mybatis环境,我使用的mybatis版本是3.5.0.然后导入相关jar包。
既然用的mybatis,当然需要mybatis的核心jar包,和lib文件下的jar包,如下图:
因为连接的是oracle数据库,所以还需要oracle的jar包,我的地址是:H:\app\zheng\product\12.2.0\dbhome_1\jdbc\lib
jar包都导入项目后,才可以正式开始。
1. 创建SqlSessionFactory
首先获取一个SqlSessionFactory,,Mybatis提供了SqlSessionFactoryBuilder来生成SqlSessionfactory,可以通过XML配置文件或者java代码去生成SqlSessionFactory。这里建议用XML来生成SqlSessionFactory,因为代码的方式会在需要修改的时候比较麻烦。
在mybaits中,因为这是基础配置文件(XML有两类,一类是基础配置文件,主要是配置上下文参数和运行环境,下面的XML就是基础配置文件,另一类就是映射文件,后面会用到),所以取名mybaits.cfg.xml。mybatis说明文档中XML代码如下:
大部分地方复制过来就可以了,只需要改一下数据源的配置,driver填OracleDriver这个驱动器类的全限定名。url的写法有多种,username,password就是连接数据库用的用户,和密码,这里就不详细说明了。 <mappers>元素代表引入哪些映射器,我们后面会用新建一个叫product.mapper.xml的映射文件。所以这里写上这个映射文件。稍微改一下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="oracle.jdbc.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:@//DESKTOP-997L86A:1521/orcl"/>
<property name="username" value="c##scott"/>
<property name="password" value="tiger"/>
</dataSource>
</environment>
</environments>
<!--映射文件-->
<mappers>
<mapper resource="product.mapper.xml"/>
</mappers>
</configuration>
然后是去生成SqlSessionFactory了。说明文档中写了可以用下面的代码去生成SqlSessionFactory:
当然这里也需要改一下,把resource换成自己刚才写的XML文件就行了。然后我是把这个方法写在一个getSqlSessionFactory静态方法里面的,这样可以方法生成SqlSessionFactory。新建MyBatisUtil类,代码如下:
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 MyBatisUtil {
public static SqlSessionFactory getSqlSessionFactory() throws IOException {
String resource = "mybatis.cfg.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
return sqlSessionFactory;
}
}
1. 创建SqlSession
然后是创建SqlSession,有了SqlSessionFactory后,创建SqlSession就很简单了,一行代码就可以,我们同样把它写在一个静态方法里面,和上面的getSqlSessionFactory()方法放在一起。代码如下:
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 MyBatisUtil {
public static SqlSessionFactory getSqlSessionFactory() throws IOException {
String resource = "mybatis.cfg.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
return sqlSessionFactory;
}
public static SqlSession getSqlSession() throws IOException {
SqlSessionFactory sqlSessionFactory=getSqlSessionFactory();
return sqlSessionFactory.openSession();
}
}
1. 创建映射器
之前说过,mybatis中XML有两类,一个是之前写的基础配置文件,还有一个就是接下来的映射器文件。映射文件可以用XML或者注解实现,这里我们同样推荐使用XML实现,因为如果同时使用XML和注解定义的话,XML会覆盖掉注解方式。而且当Sql语句比较复杂时,使用注解方式也会降低可读性,灵活性也不如XML。
映射器的主要就是将SQL查询到的结果映射为一个POJO,或者将POJO的数据插入数据库,所以需要先定义一个POJO。
这是用来测试的Testtable表格,只有一个id和名字。
对应的POJO:
public class Testtable {
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
用XML定义映射器分为两个部分:接口和XML。我在看视频的时候,老师一开始是没有讲接口的,所以这里就先不使用接口来创建映射器。那么在有了POJO后,只需要配置一下XML文件就可以实现映射器了。product.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="ProductMapper">
<select id="selectTesttable_id" parameterType="int" resultType="Testtable">
select * from Testtable where id = #{id}
</select>
<select id="selectTesttable_name" parameterType="String" resultType="Testtable">
select * from Testtable where name = #{id}
</select>
</mapper>
<mapper namespace="ProductMapper">所使用的是接口的全限定名,因为没有接口,所以这里随便写。
<select>元素就是表明查询语句了,id标识哪一条SQL。
parameterType是传递进去的参数类型,好像不写也可以。
resultType是返回类型。
#{id}表示传递进去的参数。
我这里写了两条SQL语句,分别是查询条件为id的selectTesttable_id,和查询条件为name的selectTesttable_name。Mybatis提供自动映射,可以把SQl返回的列名和POJO对应起来,
使用SqlSession发送sql
有了映射器后,就可以通过SqlSession发送SQL了。代码如下:
import org.apache.ibatis.session.SqlSession;
import java.io.IOException;
public class Test {
public static void main(String[] args) throws IOException {
SqlSession sqlSession=MyBatisUtil.getSqlSession();//获取SqlSession
Testtable testtable1=sqlSession.selectOne("ProductMapper.selectTesttable_id",003);//使用ProductMapper配置文件下的selectTesttable_id语句,查询条件为where id = 003
Testtable testtable2=sqlSession.selectOne("ProductMapper.selectTesttable_name","菜刀");//使用ProductMapper配置文件下的selectTesttable_name,查询条件为where name = ‘菜刀’
System.out.println("id="+testtable1.getId()+"名字="+testtable1.getName());
System.out.println("id="+testtable2.getId()+"名字="+testtable2.getName());
sqlSession.close();//关闭资源。
}
}
查询结果如下
selectOne方法有两个参数,一个String对象,和一个Object对象,String是由命名空间加SQL id组成的。由此来确定唯一一条SQL语句,Object由之前的<select>元素中的parameterType确定的。 selectOne方法会返回一个Testtable类型的对象,书中用了转换:
Testtable testtable1=(Testtable)sqlSession.selectOne("ProductMapper.selectTesttable_id",003);
但是实际上不用转换,可以直接使用。
注意一定要sqlSession.close();关闭资源,如果不关闭,数据库的连接资源很快就会耗费逛,整个系统就会陷入瘫痪。这就是直接用SqlSession发送SQL语句,接下来使用SqlSession去获取Mapper接口,通过Mapper接口发送语句。
使用Mapper接口发送sql
既然使用Mapper接口发送语句,那么就需要先定义一个映射器接口。代码如下
public interface TesttableMapper {
public Testtable selectTesttable_id(int id);
}
这个方法的名字就是SELECT语句id的名字,参数就是#{id}。
修改product.mapper.xml文件里的<mapper namespace="ProductMapper">,改成新建的接口名。<mapper namespace="TesttableMapper">
测试代码如下:
TesttableMapper testtableMapper=sqlSession.getMapper(TesttableMapper.class);
Testtable testtable3=testtableMapper.selectTesttable_id(002);
System.out.println("id="+testtable3.getId()+" 名字="+testtable3.getName());
sqlSession.close();
注意TesttableMapper这个接口是没有实现类的,但是mybatis运用了动态代理技术,为这个接口生成了一个代理对象。使得接口也能运行起来。
两种发送sql的方式的区别
使用Mapper发送SQl可以提高可读性,更能体现业务逻辑testtableMapper.selectTesttable_id(002)的写法也更符合面向对象的语言。而且使用Mapper,IDE会提示报错。Sqlsession去发生SQL语言只会在运行期间报错。现在基本上都是使用Mapper接口编程。