引言
ODBC(Open DataBase Connectivity : 开放数据库连接);JDBC(Java DataBase Connectivity:Java数据库连接)。
概述
众所周知,每一个java应用程序都需要直接或者间接通过JDBC实现与数据库的交互。由于信息技术的发展,传统的JDBC,由新时代的持久层框架所代替,目前适用于Java最流行的俩套持久层框架分别是hibernate和mybatis,那么由JDBC到Hibernate再到Mybatis,它们之间是如何演化替代的。
内容
一 JDBC
1 背景:JDBC是由SUN公司提出的一系列规范,但只定义了接口规范,具体的实现由各个数据库厂商去实现。
2 如何访问数据库(具体步骤)
(1)使用JDBC编程需要连接数据库,注册驱动和数据库信息,例如下面的代码展示:
public class JdbcExample
{
private Connection getConnection()
{
//创建连接对象实例并初始化
Connection connection = null;
try{
Class.forName("com.mysql.jdbc.Driver");
//数据库连接url
String url="jdbc:mysql://localhost:3036/mybatis?";
//数据库用户名
String user = "root";
//数据库密码
String password = "123456";
//JDBC API中提供的接口
connection = DriverManager.getConnection(url,user,password);
} catch (ClassNotFoundException e){
e.printStackTrace();
} catch(SQLException ex){
e.printStackTrace();
}
//返回创建的连接对象
return connection;
}
}
(2)操作Connection实例,打开Statement对象
(3)通过Statement执行SQL,返回结果到ResultSet对象
(4)使用ResultSet读取数据,通过代码转化为具体的POJO对象
(5)关闭数据库相关资源
示例代码:
public Sring getUserName(int id){
//获取一个连接对象
Connection connection = getConnection();
//创建一个statement对象,并初始化;PreparedStatement是Statement的子接口。
PreparedStatement ps = null;
//实例化一个结果集,并初始化
ResultSet rs = null;
try{
//操作Connection,打开Statement对象,执行SQL
ps= connection.preparedStatement("select userId,userName from t_user where id = ?");
ps.setInt(1,id);
//得到结果集
rs= ps.executeQuery();
String userName = rs.getString("userName");
} catch(SQLException e){
e.printStackTrace();
} finally{
rs.close();
ps.close();
connection.close();
}
return userName;
}
3 存在的弊端
(1)工作量大,每一次操作数据库都需要经过上述的访问数据库步骤。
(2)同时SQL语句易出错,降低了开发效率,存在硬编码的危险。
二 Hibernate
1 背景:为了解决JDBC存在问题,提出了一种持久化思想ORM(对象关系模型)。原理就是讲关系模型转换为对象模型,通俗讲就是把数据库关系型数据转换为POJO对象,通过操作对象来操作数据。最初SUN公司推出了JavaEE服务器端组件模型(EJB),由于EJB存在配置复杂和适用范围小的弊端,满足不了用户的需求,于是Hibernate应运而生。
2 原理:通过配置文件(或注解)可以把数据库的数据直接映射到pojo对象上,通过操作pojo对象实现对关系数据的操作。
3 特点:(1)一种全表映射的模型;(2)对JDBC封装程度较高,不需要编写SQL语句,而是编写自身的HQL语句。
4 好处:(1)消除代码的映射规则,分离到XML或者注解里面进行配置;(2)无需再管理数据库连接,也可以在XML进行配置;(3)一次数据库会话,不操作多个对象,只操作Session对象即可,关闭时也只关闭Session即可。
5 如何访问数据库?
(1)新建一个pojo的类,User.java
package com.liming.hibernate;
public class User {
private String id;
private String name;
private String password;
private String createTime;
private String expireTime;
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 String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getCreateTime() {
return createTime;
}
public void setCreateTime(String createTime) {
this.createTime = createTime;
}
public String getExpireTime() {
return expireTime;
}
public void setExpireTime(String expireTime) {
this.expireTime = expireTime;
}
}
(2)创建与User.java类对应的映射文件User.hbm.xml
?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.liming.hibernate.User">
<id name="id">
<generator class="uuid"/>
</id>
<property name="name"/>
<property name="password"/>
<property name="createTime"/>
<property name="expireTime"/>
</class>
</hibernate-mapping>
(3)编写hibernate核心配置文件,引入映射文件
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<!-- 注意中文乱码问题。如果是UTF-8照下面的更改 -->
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernate_first?useUnicode=true&characterEncoding=UTF8</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">801323</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.show_sql">true</property>
<!--
<property name="hibernate.format_sql">true</property>
-->
<mapping resource="com/liming/hibernate/User.hbm.xml"/>
</session-factory>
</hibernate-configuration>
(4) 具体业务逻辑类,添加用户
package com.liming.hibernate;
import java.util.Date;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.classic.Session;
public class Client {
public static void main(String[] arg){
//读取hibernate.cfg.xml文件
Configuration cfg = new Configuration().configure();
//建立SessionFactory,最好只创建一次,用来创建session对象
SessionFactory factory = cfg.buildSessionFactory();
//取得session
Session session = null;
try {
session = factory.openSession();
//开启事务
session.beginTransaction();
User user = new User();
user.setName("张三");
user.setPassword("123");
user.setCreateTime(new Date().toString());
user.setExpireTime(new Date().toString());
//保存User对象
session.save(user);
//提交事务
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
//回滚事务
session.getTransaction().rollback();
} finally{
if(session !=null){
if(session.isOpen()){
//关闭session
session.close();
}
}
}
}
}
三 Mybatis
1 背景:为了解决hibernate的不足,一个半自动化映射框架诞生,为什么叫做半自动化?因为它需要手工匹配提供POJO、SQL和映射关系,与Hibernate全表映射不同,加入SQL语句。其前身为iBatis,iBatis提供的持久层框架包括SQL Maps和DAO(Data Access Objects),很好解决了hibernate不足。
2 原理:mybatis根据XML配置文件创建SqlSessionFactory,SqlSessionFactory根据配置获取一个SqlSession(配置方式包括配置文件和java代码注解俩种)。SqlSession包含了sql需要的增删改查等方法,通过SqlSession实例直接运行映射文件中的sql语句,完成对数据库的访问,完成访问关闭SqlSession。
3 优点:(1)简单易学:没有第三方依赖,易于学习。
(2)灵活:mybatis不会对应用程序或数据库的现有设计附加任何影响。sql语言配置在xml文件里,便于统一管理和优化。
(3)解除sql与程序代码的耦合:通过提供DAO层,将业务逻辑和数据访问逻辑分离,使传统的设计更清晰,易于维护和单元测试。
(4)提供映射标签,支持ORM
(5)提供xml标签,支持编写动态sql。
4 缺点:(1)当字段多、关联表多时,编写SQL语句工作量大
(2)SQL语句依赖数据库,导致数据库移植性差,不易更换数据库。
(3)框架功能还有待完善,不容易适应快速数据库修改
(4)二级缓存机制不怎么好用。
5 通过mapper接口代理方式执行实例
(1)新建一个pojo类User.java
package domain;
public class User {
private int id;
private String name;
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;
}
}
(2)编写User类的配置文件User.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="User">
<select id="selectUser" parameterType="int" resultType="User">
select * from t_user where id = #{id}
</select>
</mapper>
(3)编写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>
<typeAliases>
<typeAlias alias="User" type="domain.User" />
</typeAliases>
<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/test?useUnicode=true&characterEncoding=UTF-8" />
<property name="username" value="root" />
<property name="password" value="...." />
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="domain/User.xml" />
</mappers>
(4)测试:查询一条数据
package domain;
import java.io.IOException;
import java.io.Reader;
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 domain.User;
public class Test {
public static void main(String[] args) throws IOException {
String resource = "domain/configuration.xml";
Reader reader = Resources.getResourceAsReader(resource);
SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(reader);
SqlSession session = ssf.openSession();
try {
User user = (User) session.selectOne("selectUser", "1");
System.out.println(user);
} catch (Exception e) {
e.printStackTrace();
} finally {
session.close();
}
}
(5)备注:这只是一个简单的例子,其中导入俩个包mybatis-3.0.3.jar和mysql-connector-Java-5.1.9-bin.jar。以上所有文件都放入了domain包下面。
总结
对比三种访问数据库的方式,代码量最小的是JDBC,那么最简单的方式是不是JDBC哪?其实这个回答也不是很确定,不过基本上可以回答JDBC访问数据库的方式已经很少被使用了。目前市场上用的比较多的就是hibernate和mybatis。对比hibernate和mybatis访问数据库的操作流程,基本上差不多,最大的区别还是mybatis可以灵活的加入sql语句,而hibernate对sql语句封装的程度较高,不能很好的支持。当然更深入的mybatis和hibernate还是有些区别的,后面将会深入研究mybatis,从更高级别程度来对比这俩种持久层框架。