Mybatis(一)-------

mybatis的优势:

1)、消除大量的jdbc冗余代码,包括参数设置、结果封装等

2)、sql语句可控制,方便查询优化,使用灵活

3)、学习成本低,且提供了对spring框架的集成

4)、引入缓存机制,提供了与第三方缓存类库的集成支持

单纯用mybatis开发有接口注解版、xml版

xml:MyBatis开发的详细步骤_骨灰级收藏家的博客-CSDN博客

接口注解:MyBatis学习总结(十一):MyBatis的纯注解开发_给你两窝窝的博客-CSDN博客

这里我们就不用多去关联mysql,而是使用HSQLDB数据库的内存模式作为测试数据库。

一、HSQLDB

mybatis源码中使用了HSQLDB的内存模式作为单元测试数据库(就是数据等都是基于内存),该数据库是使用java编写的,提供了一个小型的同时支持内存和磁盘存储表结构的数据库引擎,支持server模式和内存模式两种方式。

server模式是把HSQLDB作为一个单独的数据库服务运行,类似于我们常见的mysql、oracle等,而内存模式是把HSQLDB嵌入应用中,这儿模式只能存储应用内部数据,但如果应用进程结束,HSQLDB的数据也会丢失,因此这种模式只适合做单元测试。

我们下面开始测试HSQLDB:

pom文件:

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.hsqldb</groupId>
            <artifactId>hsqldb</artifactId>
            <version>2.4.0</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
    </dependencies>

测试类:

package com.blog4java.hsqldb;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.jdbc.ScriptRunner;
import org.apache.ibatis.jdbc.SqlRunner;
import org.junit.Before;
import org.junit.Test;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

public class Example01 {
    private Connection conn = null;
    @Before
    public void initData() {
        try {
            // 加载HSQLDB驱动
            Class.forName("org.hsqldb.jdbcDriver");
            // 获取Connection对象
            conn = DriverManager.getConnection("jdbc:hsqldb:mem:mybatis",
                    "sa", "");
            // 使用Mybatis的ScriptRunner工具类执行数据库脚本
            ScriptRunner scriptRunner = new ScriptRunner(conn);
            scriptRunner.setLogWriter(null);
            //读取resource目录下的文件(依赖的项目的resource目录也会读到)
            scriptRunner.runScript(Resources.getResourceAsReader("create-table.sql"));
            scriptRunner.runScript(Resources.getResourceAsReader("init-data.sql"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Test
    public void testHsqldbQuery() {
        // SqlRunner是Mybatis封装的操作数据库的工具类
        SqlRunner sqlRunner = new SqlRunner(conn);
        try {
            //调用SqlRunner类的selectAll()方法查询数据
            List<Map<String, Object>> results = sqlRunner.selectAll("select * from user");
            results.forEach(System.out::println);
            sqlRunner.closeConnection();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

sql脚本:

create-table.sql:

drop table user if exists;
create table user (
  id int generated by default as identity,
  create_time varchar(20) ,
  name varchar(20),
  password varchar(36),
  phone varchar(20),
  nick_name varchar(20),
  primary key (id)
);

init-data.sql:

insert into user (create_time, name, password, phone, nick_name) values('2010-10-23 10:20:30', 'User1', 'test', '18700001111', 'User1');
insert into user (create_time, name, password, phone, nick_name) values('2010-10-24 10:20:30', 'User2', 'test', '18700001111', 'User2');
insert into user (create_time, name, password, phone, nick_name) values('2010-10-25 10:20:30', 'User3', 'test', '18700001111', 'User3');
insert into user (create_time, name, password, phone, nick_name) values('2010-10-26 10:20:30', 'User4', 'test', '18700001111', 'User4');
insert into user (create_time, name, password, phone, nick_name) values('2010-10-26 10:20:30', 'User5', 'test', '18700001111', 'User4');
insert into user (create_time, name, password, phone, nick_name) values('2010-10-26 10:20:30', 'User6', 'test', '18700001111', 'User4');
insert into user (create_time, name, password, phone, nick_name) values('2010-10-26 10:20:30', 'User7', 'test', '18700001111', 'User4');
insert into user (create_time, name, password, phone, nick_name) values('2010-10-26 10:20:30', 'User8', 'test', '18700001111', 'User4');
insert into user (create_time, name, password, phone, nick_name) values('2010-10-26 10:20:30', 'User9', 'test', '18700001111', 'User4');
insert into user (create_time, name, password, phone, nick_name) values('2010-10-26 10:20:30', 'User10', 'test', '18700001111', 'User4');
insert into user (create_time, name, password, phone, nick_name) values('2010-10-26 10:20:30', 'User11', 'test', '18700001111', 'User4');
insert into user (create_time, name, password, phone, nick_name) values('2010-10-26 10:20:30', 'User12', 'test', '18700001111', 'User4');
insert into user (create_time, name, password, phone, nick_name) values('2010-10-26 10:20:30', 'User13', 'test', '18700001111', 'User4');
insert into user (create_time, name, password, phone, nick_name) values('2010-10-26 10:20:30', 'User14', 'test', '18700001111', 'User4');

log4j.properties:

log4j.rootLogger=INFO, stdout

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.Threshold=INFO
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c,%L] - %m%n

运行下测试类:

此时就能正常使用HSQLDB了。

二、JDBC

 jdbc(java database connectivity)是java提供的访问关系型数据库的接口(当然也可以访问一些文件系统之类的,只要该数据源提供jdbc规范的驱动即可),在java编写的应用里,JDBC API可以执行sql语句、检索sql执行结果、将数据更改写会底层数据源等操作,JDBC API也可以用于分布式、易购的环境下与多个数据域交互。

自1997年java语言引入jdbc规范后,各大数据库厂商开始提供JDBC驱动的实现。

使用JDBC操作数据源大致需要以下步骤:

1)、与数据源建立连接

2)、执行sql语句

3)、检索sql执行结果

4)、关闭连接

----------------------------------------1、建立数据源连接

1、Connection接口

JDBC中定义了一个Connection接口,用来表示与底层数据源的连接,JDBC程序可以用下面两种方式获取Connection对象。

1)、DriverManager(不常用):在JDBC1.0规范就存在,由JDBC API实现的驱动管理类,当程序应用第一次尝试通过URL连接数据源时,DriverManager会自动加载Classpath下的所有JDBC驱动。DriverManager中提供了一些重载方法用来获取Connection对象(getConnection)例如:

Connection con = DriverManager.getConnection("jdbc:hsqldb:men:mybatis", "sa", "");

2)、DataSource(主流):这个接口是在JDBC2.0规范应引入的api,该接口比DriverManager跟受欢迎,因为它提供了更多底层数据源相关的细节,并且应用不在需要去关注JDBC驱动的实现,一个DataSource代表着一个数据源,当DataSource对象的getConnection() 方法被调用会返回一个和数据源建立连接的Connection对象。

我们此时就可以通过修改DataSoucce对象的属性,从而使得该对象获取到指向不同的数据源的Connection对象。

需要注意的是JDBC API只提供了DataSource接口,没有提供DataSource的具体实现,其具体实现由JDBC驱动程序提供(一些主流的数据库连接池Druid、DBCP、C3P0也会提供DataSource接口的具体实现)。

mybatis中有提供了对DataSource接口的实现,我们使用mybatis可以这么去使用:

 另外mybatis还提供看DataSource的工厂,即DataSourceFactory(主流),我们可以用工厂模式去创建DataSource实例,例如:

 2、其他接口

JDBC API还提供了两个DataSource接口比较重要的扩展,用于支撑企业级应用:

1)、ConnectionPoolDataSource:池化,支持缓存和复用Connection对象,这样能够很大程度提升应用性能和伸缩性。

2)、XADataSource:实例返回的ConnectionSource对象能够支持分布式事务。

注意:JDBC4.0之前的版本,创建Connection对象之前,应用程序需要显式的加载驱动类,具体代码:

Class.forName("org.hsqldb.jdbcDriver");

------------------------------------2、执行sql语句

上面我们已经获取到Connection对象,下一步的需要做的是对目标数据源执行查询和更新操作。              JDBC API提供了一些访问SQL规范常用的实现特性,然而不同的厂商对这些特性的支持程度不同,所以JDBC提供了一个DataBaseMetadata接口,我们可以使用该对象来确认目前使用的数据源是否支持这一特性。(JDBC还提供了转义语法,可以让我们调用各大厂商提供的自己定义的特性)。

获取到Connection对象后,我们可以通过该对象设置事务属性等操作,并且通过通过该接口提供的方法创建出Statement、PreparedStatement、CallableStatement对象。

Statement可以理解为JDBC提供的Sql语句的执行器,可以调用接口中定义的executeQuery、executeUpdate等方法执行查询、修改操作。还可以调用executeBatch方法执行批量处理操作,也可以调用通用方法execute执行查询、修改语句。执行完后会返回一个ResultSet结果集对象。或者我们可以手动的通过getResultSet方法获取结果集,用getUpdateCount方法获取受影响行。

下面是一个执行sql语句的例子:

-------------------------------------3、处理sql执行结果

上面执行完sql后会获取到一个ResultSet结果集对象,我们可以遍历该结果集,然后通过ResultSet提供的一系列getXXX方法去获取想要的数据。

------------------------------------4、使用JDBC操作数据库的完整流程

我们可以用下面的例子来使用jdbc操作数据库:

 首先jdbc4.0之前需要显式加载驱动类,然后获取Connection对象,执行sql。获取到ResultSet对象,通过ResultSet对象获取刀片ResultSetMetaData对象(存放 ResultSet 对象中列的类型和属性信息),然后对其进行遍历获取数据信息。最后对连接进行关闭。

此时可以看控制台打印:

ResultSet和ResultSetMetaData的区别:有关ResultSetMetaData与ResultSet_Programming.的博客-CSDN博客

二、JDBC API中的类和接口

jdbc api主要由java.sql、javax.sql两个包构成

1、java.sql包

该包下主要由如下接口、枚举、类:

 

我们主要需要关心的是下面几个接口:

 这些接口都继承java.sql.Wrapper接口。Wrapper接口提供了两个接口为各大厂商提供访问原始类型的功能,从而JDBC驱动中自己定义的一些非标准特性(就是调用驱动提供商自己定义的一些特性扩展接口)

 1)、unwrap方法:可以获取未经过保证的JDBC驱动原始类型对象,我们可以通过该对象调用JDBC驱动中提供的非标准方法

2)、isWrapperFor方法:可以判断当前实例是否是JDBC驱动中某一类型的保证类型

下面是一个实例:

 上面的代码就是调用oracle驱动中提供的非JDBC标准的方法。

注意:JDBC API中的Connection、Statement、ResultSet等接口都继承Wrapper接口,这些接口都提供了对JDBC驱动原始类型的访问能力 

 2、javax.sql包

JDBC2.0版本的可选包提供,主要的类、接口等:

1)、DataSource接口 

JDBC1.0中使用了DriverManager类来产生一个Connection对象,而JDBC2.0提供了一个DataSource接口用来更好的连接数据源。

首先应用程序不需要像DriverManager一样对加载数据库程序信息进行硬编码,开发人员可以通过JNDI注册这个数据源对象,然后在程序中使用一个逻辑名称来引用它,JNDI会自动根据我们给出的名称找到与这个名称绑定的DataSource对象,然后我们就可以使用这个DataSource对象来建立和具体数据库的连接了。

其次,DataSource接口的第二个优势体现在连接池和分布式事务上。

2)、PooledConnection接口

javax.sql下还提供了一个PooledConnection接口(池化接口),PooledConnection和Connection不同之处在于提供了连接池管理的句柄,前者在使用完之后不用关闭它,有连接池统一管理。

而我们一般开发中不会直接使用这个PooledConnection接口,而是通过第三方管理连接池的中间层(例如Durid),前面我们讲到调用DataSource接口的getConnection方法获取Connection对象,而当我们使用例如Durid第三方连接池中间层时,该对象实际就是PooledConnection类型,每个PooledConnection对象对应一个物理连接。连接池会对这些对象进行统一创建回收等工作,如果不存在可用的PooledConnection对象,连接池管理器会调用ConnectionPoolDataSource对象的getConnection方法创建获取PooledConnection对象。

连接池可以通过调用PooledConnection对象的addConnectionEventListener()将自己注册成一个监听者,当数据库连接需要重用或者关闭时会产生一个ConnectionEvent对象,该对象表示一个连接事件,此时连接池就会接到通知并执行相应实现。

3)、分布式事务相关接口

另外该包下还有一些关于分布式事务的接口:XADataSource、XARsource、XAConnection。XAConnection接口继承PooledConnection接口,因此它具备有PooledConnection的特性。

4)、RowSet接口

Javax.sql中还提供了一个RowSet接口,该接口继承自java.sql下的ResultSet接口,RowSet用于数据源和应用程序的数据的一个映射。RowSet可以建立一个与数据源的连接并在整个生命周期都维持其连接(称为连接的RowSet),也可以连接后获取数据就进行关闭(称为非连接RowSet)然后进行数据操作,操作完成后重新连接数据源将数据更新到数据库(中间减少了占用数据源资源,而是先断开在内存中进行数据操作后再重新连接更新数据源),相较与ResultSet,RowSet的离线操作可以利用应用内存减轻数据库的压力,由于数据操作都是在应用内存中进行的,然后批量提交到数据源,所以性能会有较大的提升。

具体区别:https://www.cnblogs.com/myitnews/p/11846087.html

aaa

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值