两个ORM框架比较
Hibernate
Hibernate自EJB之后出现,对JDBC的封装程度较高,是全表映射的,需要提供POJO和映射关系(XML或注解)。
Hibernate优点:
- 映射规则从程序中分离到XML或注解中。
- 无需管理数据库连接。
- 一个会话中只要操作Session对象(JDBC需要操作ResultSet、Statement、Connection)。
- 支持级联、缓存、映射。
Hibernate缺点:
- 全表映射不便,如更新时还需其它没被更新的字段。
- 根据不同条件组装SQL不便。
- 多表联结的复杂SQL不便。
- 对存储过程支持差。
- HQL性能较差。
MyBatis
MyBatis是半自动的ORM框架,不仅需要提供POJO和映射关系,还需要书写SQL语句。
MyBatis优点:
- 可以配置动态SQL。
- 可以优化SQL。
- 对存储过程支持好。
- 对复杂的和需要优化性能的SQL实现较方便。
- SQL写在XML里,相比JDBC,能解除SQL与程序代码的耦合。
MyBatis缺点:
- 配置比Hibernate更繁杂。
- SQL语句依赖于数据库,导致数据库移植性差。
认识MyBatis的基本构成
- SqlSessionFactory:这是一个用来创建
SqlSession
会话对象的工厂接口,它常使用的实现类是DefaultSqlSessionFactory
,但这个实现类往往对使用者透明。 - SqlSessionFactoryBuilder:这个类的对象是直接
new
出来的,用它的build()
方法,传入MyBatis配置信息的输入流就可以建立前面的工厂对象了。 - SqlSession:类似于Hibernate的Session,它也是指和数据库交互的会话,不过它是一个接口。它的实现类的对象可以直接反射接口里的方法,也可以获取映射器接口实现对象,然后用里面的方法。
- *Mapper:映射器,由一个接口和一个XML映射文件组成,其中在XML映射文件中会指明相应的映射器接口是哪个,并在里面给出要使用的SQL语句。这个XML映射文件又会被注册到MyBatis配置文件中。所以只要读取配置文件,就能获取到MyBatis相关的一切配置。
映射器也可以用一个接口和相应的Annotation注解实现,但这种方式可读性差,不适合复杂的SQL。
MyBatis的下载和在IDEA下的使用
获取MyBatis
MyBatis的JAR包可以在GitHub上下载,我下载了两天一直下载失败,最后群里的好心人帮下载了。下载好解压后将其核心JAR包和其中的依赖JAR包一并加载到工程里即可。
配置IDEA数据库连接
有关SQL方言
如果在后面使用时写SQL时出现:
只要Alt+Enter
配置一下方言即可:
一个查询的例子
目录结构
创建数据库表
model.Student(实体类)
只记录其属性,还要提供无参构造器和getter、setter方法。
private Integer id;
private String stuName;
mapper.StudentMapper(映射器接口)
package mapper;
import model.Student;
//Student类的映射器接口
public interface StudentMapper {
Student getStudent(int id);
}
mapper/StudentMapper.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="mapper.StudentMapper">
<!--用select元素定义一个查询SQL,id用接口中的方法名-->
<!--parameterType指定传入的参数类型,resultType指定返回的参数类型,参数类型可用别名(配置文件中定义的)-->
<select id="getStudent" parameterType="int" resultType="stu">
SELECT
id,
name AS stuName
FROM student
WHERE id = #{id}
</select>
</mapper>
对这里独特的SQL语句进行一下解释:
SELECT
id, #这里相当于id AS id
name AS stuName #这里stuName是模型类的属性,name则是实际数据库中表的列
FROM student
WHERE id = #{id} #这里#{}内的id是传入给getStudent函数的参数名称
注意,不能在映射文件中为SQL打上这些注释(所以拿出来解释),不然会报错。
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>
<!--为实体类定义别名,这样后面在MyBatis上下文提到这个实体类就不用这么长的完整类名了-->
<typeAliases>
<typeAlias type="model.Student" alias="stu"/>
</typeAliases>
<!--提供数据库信息,默认使用development数据库构建环境-->
<environments default="development">
<environment id="development">
<!--使用JDBC事务管理-->
<transactionManager type="JDBC"/>
<!--使用连接池方式来获取连接对象-->
<dataSource type="POOLED">
<!--数据库驱动-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<!--连接字符串-->
<property name="url" value="jdbc:mysql://localhost:3306/test_mbts"/>
<!--用户名-->
<property name="username" value="root"/>
<!--密码-->
<property name="password" value="3838438"/>
</dataSource>
</environment>
</environments>
<!--注册映射器(只指明xml映射文件,而相应的映射器接口会从映射文件中获取)-->
<mappers>
<mapper resource="mapper/StudentMapper.xml"/>
</mappers>
</configuration>
Main(含main方法的主类)
import model.Student;
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 Main {
public static void main(String[] args) {
//一个打开的SqlSession接口的实现类对象将接受用户的需求,将需求提供给底层的Executor接口完成操作
//这里拿出try块声明是为了在finally块中对其正常关闭
SqlSession sqlSession = null;
try {
//读取XML配置文件信息到输入流,配置文件中已经注册了映射器(Mapper)
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
//利用配置信息建立SqlSessionFactory(工厂接口)的实现类对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//获取打开的SqlSession对象
sqlSession = sqlSessionFactory.openSession();
//不用获取映射器,用iBatis遗留的方式,即调用SqlSession对象的方法
//第一个参数字符串是映射器配置文件中的"namespace"拼接"id",即"接口的全限名.使用的方法名"
//如果这个方法是唯一的,可以只写方法名
Student student = sqlSession.selectOne("mapper.StudentMapper.getStudent", 2);
System.out.println(student.getId() + "," + student.getStuName());
} catch (IOException e) {
e.printStackTrace();
} finally {
//在finally块中关闭打开的SqlSession对象
if (null != sqlSession)
sqlSession.close();
}
}
}
因为这个例子只是做了查询,所以不用在try-catch
块里考虑commit
提交和rollback
回退。
运行结果
log4j的日志警告后面再学吧。