JDBC实战(六)数据源、连接池、代理模式、动态代理

连接池、代理模式、动态代理

1、数据源和连接池

所谓数据源也就是数据的来源。它存储了所有建立数据库连接需要的信息。算是对数据库的一个抽象映射,即一个数据源对于一个数据库。

数据源有以下属性

  1. databaseName String数据库名称,即数据库的SID。
  2. dataSourceName String数据源接口实现类的名称。
  3. description String 对数据源的描述。
  4. networkProtocol String 和服务器通讯使用的网络协议名。
  5. password String 用户登录密码。
  6. portNumber数据库服务器使用的端口。
  7. serverName String数据库服务器名称。
  8. user String 用户登录名。

如果数据是水,数据库就是水库,数据源就是连接水库的管道,终端用户看到的数据集是管道里流出来的水。

Java Web服务器开始时,我们用的最多的数据源是JNDI。

数据库连接池
Web服务器中一般都是配置数据源,然后每个数据源维护一些数据库连接池。我们知道,数据库连接的创建时非常耗时耗资源的,还会受到网速的影响。我们在配置数据源的时候一般都已经配置好数据库连接池的参数,然后数据源会自动帮我们维护这些。所有这些对开发者而言是透明的。连接池是由容器(比如Tomcat)提供的,用来管理池中的连接对象。连接池自动分配连接对象并对闲置的连接进行回收。连接池中的连接对象是由数据源(DataSource)创建的。连接池(Connection Pool)用来管理连接(Connection)对象。

DataSource 通常被称为数据源,它包含连接池和连接池管理两个部分,习惯上也经常把 DataSource 称为连接池。

在这里插入图片描述

参考博客
数据源和连接池
连接池、数据源、JNDI三者间的关系及用法

1、创建基本的数据源类

我们在之前编写的代码里边,每次都是创建连接,然后实现了一些简单的目的以后就关掉了connection。但创建连接的过程是开销很大的。我们可以用连接池的方法,使得当连接数目变多时,建立的数据库连接能重用从而优化效率。

1、创建基本的DataSource类

public class DataSource {
    private static String user = "root";
    private static String password = "123";
    private static String DB_URL =  "jdbc:mysql://localhost:3306/test?serverTimezone=UTC";
    private  LinkedList<Connection> connectionsPool;//连接池
    private  int InitCount = 5;//初始化连接池的容
    private  int MAXCONNECTION=10;//最大连接数
    private  int currentCount=0;//当前创建的连接数

    public DataSource(){
        try{
            connectionsPool = new LinkedList<>();
            for(int i=0;i<InitCount;i++){
                connectionsPool.addLast(createConnection());
                currentCount++;
            }
        } catch (SQLException e) {
            throw new ExceptionInInitializerError("创建连接失败,已创建数目:"+currentCount);
        }
    }
    private static Connection createConnection() throws SQLException {
        return DriverManager.getConnection(DB_URL,user,password);
    }
    public Connection getConnection() throws SQLException {
        synchronized (DataSource.class){
            if(this.connectionsPool.size()>0){
                return this.connectionsPool.removeFirst();
            }else if(currentCount<MAXCONNECTION){
                this.connectionsPool.addLast(createConnection());
                currentCount++;
                return this.connectionsPool.removeFirst();
            }else
                throw new SQLException("已经达到最大的连接数!无法创建连接!");
        }

    }
    public  void free(Connection conn){
        this.connectionsPool.addLast(conn);//尾插法
      
    }

}

我们的连接都存放在一个LinkedList里面。

2、修改之前的JDBCUtils类

public final class JDBCUtils {
    private static DataSource dataSource=new DataSource();
    public static Connection getConnect() throws SQLException {//异常应该抛出
        //return DriverManager.getConnection(DB_URL, user, password);
        return dataSource.getConnection();
    }

    static{//使用class.forName()方法一般用于静态代码块,而且该方法注册驱动不依赖具体的类库
        try {
            //forName进行类的加载时优先加载静态代码块。
            Class.forName("com.mysql.cj.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    public static void free(Connection conn, Statement st, ResultSet res) {
        try {
            if (res != null) //原则1:晚点连接早点释放。原则2:先创建的后释放
                res.close();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            if (st != null)
                try {
                    st.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                } finally {
                    if (conn != null)
                        try {
                            //conn.close();
                            dataSource.free(conn);//重用,将创建的连接不关闭,而是将其回收到连接池
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                }
        }
    }
}

3、简单测试

public class Test_1 {
    public static void main(String[]args) throws SQLException {
        for(int i=0;i<20;i++){
            Connection conn = JDBCUtils.getConnect();
            System.out.println(conn);
            JDBCUtils.free(conn,null,null);
        }
    }
}

我们设置了连接个数最大只有10个。
在这里插入图片描述

2、使用代理模式来保持因使用数据源连接池导致的用户关闭不习惯问题

我们看一下现在的JDBCUtils的代码中free()函数:

 public static void free(Connection conn, Statement st, ResultSet res) {
        try {
            if (res != null) //原则1:晚点连接早点释放。原则2:先创建的后释放
                res.close();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
           
                try {
                	 if (st != null)
                    	st.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                } finally {
                    if (conn != null)
                        try {
                            //conn.close();
                            dataSource.free(conn);//重用,将创建的连接不关闭,而是将其回收到连接池
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                }
        }

如果有些人没有用到我们在线程池里边写的free,那会导致连接池的连接数目越用越少。故我们需要修改以下,以适应使用习惯。

下面是代理模式,来源于菜鸟教程

  1. 在代理模式(Proxy Pattern)中,一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口。
  2. 介绍
  • 意图:为其他对象提供一种代理以控制对这个对象的访问。
  • 主要解决:在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上。在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层。
  • 何时使用:想在访问一个类时做一些控制。
  • 如何解决:增加中间层。
  • 关键代码:实现与被代理类组合。
  • 应用实例: 1、Windows 里面的快捷方式。 2、猪八戒去找高翠兰结果是孙悟空变的,可以这样理解:把高翠兰的外貌抽象出来,高翠兰本人和孙悟空都实现了这个接口,猪八戒访问高翠兰的时候看不出来这个是孙悟空,所以说孙悟空是高翠兰代理类。 3、买火车票不一定在火车站买,也可以去代售点。 4、一张支票或银行存单是账户中资金的代理。支票在市场交易中用来代替现金,并提供对签发人账号上资金的控制。 5、spring aop。
  • 优点: 1、职责清晰。 2、高扩展性。 3、智能化。
  • 缺点: 1、由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。 2、实现代理模式需要额外的工作,有些代理模式的实现非常复杂。
  • 使用场景:按职责来划分,通常有以下使用场景:
    1、远程代理。 2、虚拟代理。 3、Copy-on-Write 代理。 4、保护(Protect or Access)代理。 5、Cache代理。 6、防火墙(Firewall)代理。 7、同步化(Synchronization)代理。 8、智能引用(Smart Reference)代理。
  • 注意事项: 1、和适配器模式的区别:适配器模式主要改变所考虑对象的接口,而代理模式不能改变所代理类的接口。 2、和装饰器模式的区别:装饰器模式为了增强功能,而代理模式是为了加以控制。

参考:代理模式|菜鸟教程

Connection在JDBC里是一个接口,而各个厂商的对应设计的Connection则是实现该接口的实体类。
那么我们的代理类则需要内部有这样的一个类来完成实际的功能。

1、我们需要创建一个Proxy_MyConnection 类,来代理Connection
我们要做的就是将close方法重写,不是关闭,而是把它放回到连接池里边。它是无参数的。所以我们需要这个类内部具有一个连接池。故 部分实现代码如下:

/**
 * 代理Connection类
 */
public class Proxy_MyConnection implements Connection {//首先得实现该接口
    private Connection realConnection;//所代理的类
    private DataSource2 dataSource2;//连接池
    private int currentUser = 0;//记录当前连接了多少个客户

    /**
     * @param conn  代理接口
     * @param pool2 连接池
     */
    Proxy_MyConnection(Connection conn, DataSource2 pool2) {//构造器,别人构造不出来。只有同一包内才能构造。
        this.realConnection = conn;
        this.dataSource2 = pool2;
    }

    @Override
    public void close() throws SQLException {
        //最大连接
        int maxConnect = 5;
        if (currentUser < maxConnect) {
            this.currentUser++;
           // System.out.println("user"+currentUser);
            this.dataSource2.connectionPool.addLast(this);//this就是代理接口类
        } else {
            this.realConnection.close();//最大连接数已经达到。我们真的需要关闭了。
            this.currentUser--;
        }

    }
    @Override
    public Statement createStatement() throws SQLException {
        return this.realConnection.createStatement();//使用实际的JDBC connection接口的方法。提高可用性
    }
    ......
    ......

2、我们需要修改连接池DataSource类的一些代码,第一个是创建连接的方法,第二个是获取连接的方法

	//创建连接
    private  Connection createConnection() throws SQLException {
        Connection conn = DriverManager.getConnection(DB_URL,user,password);
        Proxy_MyConnection proxy_conn = new Proxy_MyConnection(conn,this);
        return proxy_conn;//代理类
    }
    //获取连接
    public Connection getConnection() throws SQLException {
        synchronized (DataSource.class){
            if(this.connectionPool.size()>0){
                return this.connectionPool.removeFirst();
            }else if(currentCount<MAXCONNECTION){
                this.connectionPool.addLast(createConnection());
                currentCount++;
                return this.connectionPool.removeFirst();
            }else
                throw new SQLException("已经达到最大的连接数!无法创建连接!");
        }

    }

在这里插入图片描述

此时JDBCUtils的free方法变为我们所习惯的直接close()

public static void free(Connection conn, Statement st, ResultSet res) {
        try {
            if (res != null) //原则1:晚点连接早点释放。原则2:先创建的后释放
                res.close();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
                try {
                	if (st != null)
                    	st.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                } finally {
                    if (conn != null)
                        try {
                            conn.close();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                }
        }

3、测试代码

 		for(int i=0;i<5;i++){
            Connection conn = JDBCUtils.getConnect();
            System.out.println(conn);
            JDBCUtils.free(conn,null,null);
        }
        System.out.println("测试是否可用重用:");
        for(int i=0;i<5;i++){
            Connection conn = JDBCUtils.getConnect();
            System.out.println(conn);
            JDBCUtils.free(conn,null,null);
        }

现在使用的都是我们的代理类Proxy_MyConnection
在这里插入图片描述

3、使用动态代理完善连接代理

通过上面的代码我们知道Proxy_MyConnection是代理了Connection类的功能。而且内部含有一个真正的实例类realConnection,我们所有的实现方法都是调用该内部实例类的方法。如:

Proxy_MyConnection的内部属性值:

private Connection realConnection;//所代理的类————
private DataSource2 dataSource2;//连接池
private int currentUser = 0;//记录当前连接了多少个客户

实现的方法:都是调用了realConnection的方法。

 @Override
    public String nativeSQL(String s) throws SQLException {
        return this.realConnection.nativeSQL(s);
    }

    @Override
    public void setAutoCommit(boolean b) throws SQLException {
        this.realConnection.setAutoCommit(b);
    }

    @Override
    public boolean getAutoCommit() throws SQLException {
        return this.realConnection.getAutoCommit();
    }

    @Override
    public void commit() throws SQLException {
        this.realConnection.commit();
    }

    @Override
    public void rollback() throws SQLException {
        this.realConnection.rollback();
    }

所以这样的操作是很繁琐的。我们本来就是用DataSource来创建连接池,维护连接池。则只关心了其close方法的实现。为了让connection能够可重用而重修改了close方法:

 @Override
    public void close() throws SQLException {
        //最大连接
        int maxConnect = 5;
        if (currentUser < maxConnect) {
            this.currentUser++;
            // System.out.println("user"+currentUser);
            this.dataSource2.connectionPool.addLast(this);//this就是代理接口类
        } else {
            this.realConnection.close();//最大连接数已经达到。我们真的需要关闭了。
            this.currentUser--;
        }

    }

为了解决这个问题,我们可用使用动态代理模式。

3.1、什么是动态代理

动态代理在Java中有着广泛的应用,比如Spring AOP、Hibernate数据查询、测试框架的后端mock、RPC远程调用、Java注解对象获取、日志、用户鉴权、全局性异常处理、性能监控,甚至事务处理等。
Java中两种常见的动态代理方式:JDK原生动态代理和CGLIB动态代理。Java动态代理与java反射机制关系紧密,毕竟是运行时创建类

代理模式:给某一个对象提供一个代理,并由代理对象来控制对真实对象的访问。代理模式是一种结构型设计模式。代理模式角色分为 3 种:

  • Subject(抽象主题角色):定义代理类和真实主题的公共对外方法,也是代理类代理真实主题的方法;
  • RealSubject(真实主题角色):真正实现业务逻辑的类;
  • Proxy(代理主题角色):用来代理和封装真实主题;

代理模式的结构比较简单,其核心是代理类,为了让客户端能够一致性地对待真实对象和代理对象,在代理模式中引入了抽象层
在这里插入图片描述
代理模式按照职责(使用场景)来分类,至少可以分为以下几类:1、远程代理。 2、虚拟代理。 3、Copy-on-Write 代理。 4、保护(Protect or Access)代理。 5、Cache代理。 6、防火墙(Firewall)代理。 7、同步化(Synchronization)代理。 8、智能引用(Smart Reference)代理等等。

如果根据字节码的创建时机来分类,可以分为

  • 静态代理
    所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和真实主题角色的关系在运行前就确定了。
  • 动态代理
    而动态代理的源码是在程序运行期间由JVM根据反射等机制动态的生成,所以在运行前并不存在代理类的字节码文件

参考博客:Java 动态代理详解

3.2、使用动态代理来实现Proxy_MyConnection类

创建Proxy_MyConnectionHandler类,用于产生代理类。

public class Proxy_MyConnectionHandler implements InvocationHandler {//必须实现该接口。
    private DataSource2 dataSource2;
    private int currentUser = 0;//记录当前连接了多少个客户
    private Connection realConnection;
    private Connection warpedConnection;

    public Proxy_MyConnectionHandler(DataSource2 dataSource) {
        this.dataSource2 = dataSource;
    }
    /**
     * 用于绑定真正的实现类
     *
     * @param realConnection 真正的连接
     * @return 返回包裹后的类,代理类。
     */
    Connection bind(Connection realConnection) {//用于绑定真正的连接realConnection
        this.realConnection = realConnection;
        this.warpedConnection = (Connection) Proxy.newProxyInstance(this.getClass().getClassLoader(),
                new Class[]{Connection.class}, this);
        return this.warpedConnection;
    }
    /**
     * 我们关心的方法,我们现在只重写close方法。利用了反射。
     */
    @Override
    public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
        if ("close".equals(method.getName())) {//只要有人调用该方法,就拦截下来进行以下操作。
            //最大连接
            int maxConnect = 5;
            if (currentUser < maxConnect) {
                this.currentUser++;
                // System.out.println("user"+currentUser);
                this.dataSource2.connectionPool.addLast(this.warpedConnection);//this就是代理接口类
            } else {
                this.realConnection.close();//最大连接数已经达到。我们真的需要关闭了。
                this.currentUser--;
            }
        }
        return method.invoke(this.realConnection, objects);//调用该方法。
    }
}

注意该方法:

  Connection bind(Connection realConnection) {//用于绑定真正的连接realConnection
        this.realConnection = realConnection;
        this.warpedConnection = (Connection) Proxy.newProxyInstance(this.getClass().getClassLoader(),
                new Class[]{Connection.class}, this);
        return this.warpedConnection;
    }

Proxy.newProxyInstance()专门给我们动态生成真正的类的方法,这里就相当于实现了Connection的所有的类似方法。new Class[]{Connection.class}表示要实现方法的类。用warpedConnection来包装。

如实现rollback方法,原来要我们手写:

  @Override
    public void rollback() throws SQLException {
        this.realConnection.rollback();
    }

这个invoke方法就是我们用来拦截我们想要拦截重写的方法。这里我们需要拦截的是close方法。并将其重写。

 public Object invoke(Object o, Method method, Object[] objects) throws Throwable

静态代理的缺点
虽然静态代理实现简单,且不侵入原代码,但是,当场景稍微复杂一些的时候,静态代理的缺点也会暴露出来。

  • 1、 当需要代理多个类的时候,由于代理对象要实现与目标对象一致的接口,有两种方式:
    只维护一个代理类,由这个代理类实现多个接口,但是这样就导致代理类过于庞大
    新建多个代理类,每个目标对象对应一个代理类,但是这样会产生过多的代理类
  • 2、 当接口需要增加、删除、修改方法的时候,目标对象与代理类都要同时修改,不易维护。

测试代码
1、现修改数据源DataSource的代码,使用动态代理:

  private  Connection createConnection() throws SQLException {
        Connection conn = DriverManager.getConnection(DB_URL,user,password);
       /* Proxy_MyConnection proxy_conn = new Proxy_MyConnection(conn,this);
        return proxy_conn;//代理类*/
        //生成代理类:
       Proxy_MyConnectionHandler proxy = new Proxy_MyConnectionHandler(this);//传入的是数据源
        return proxy.bind(conn);//绑定。
    }

2、测试

 for(int i=0;i<10;i++){
            Connection conn = JDBCUtils.getConnect();
            System.out.println(conn);
            JDBCUtils.free(conn,null,null);

运行结果:
在这里插入图片描述
我们换回原来写的静态代理类Proxy_MyConnection
在这里插入图片描述
再运行测试:
在这里插入图片描述
发现了没有:打印的包信息不同。使用动态代理得到的包信息都是MySQL的驱动包信息。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
本书是讲述iBATIS框架的权威著作。书中既详实地介绍了iBATIS的设计理念和基础知识,也讨论了动态SQL、高速缓存、DAD框架等高级主题,还讲解了iBATIS在实际开发中的应用。书的最后给出了一个设计优雅、层次清晰的示例程序JGameStore,该示例涵盖全书的大部分知识点,可以作为iBATIS学习和Web开发的经典案例,非常值得深入研究。 本书既可为广大的开发人员(不仅仅是Web应用程序开发人员)提供指导,也可为架构师的项目决策提供参考。项目经理、数据库管理员、质量保证员与测试员以及系统分析师也能从本书中受益。 目录: 第一部分 介绍 第1章 iBATIS的理念 2 1.1 一个结合了所有优秀思想的混合型解决方案 2 1.1.1 探索iBATIS的根源 3 1.1.2 理解iBATIS的优势 7 1.2 iBATIS适合应用在何处 10 1.2.1 业务对象模型 11 1.2.2 表现层 11 1.2.3 业务逻辑层 12 1.2.4 持久层 13 1.2.5 关系数据库 15 1.3 使用不同类型的数据库 17 1.3.1 应用程序数据库 17 1.3.2 企业数据库 18 1.3.3 私有数据库 19 1.3.4 遗留数据库 20 1.4 iBATIS如何解决数据库的常见问题 20 1.4.1 所有权与控制 20 1.4.2 被多个分散的系统访问 21 1.4.3 复杂的键和关系 21 1.4.4 数据模型的去规范化或过度规范化 22 1.4.5 瘦数据模型 23 1.5 小结 24 第2章 iBATIS是什么 26 2.1 映射SQL语句 27 2.2 iBATIS如何工作 29 2.2.1 iBATIS之于小型、简单系统 30 2.2.2 iBATIS之于大型、企业级系统 31 2.3 为何使用iBATIS 31 2.3.1 简单性 32 2.3.2 生产效率 32 2.3.3 性能 32 2.3.4 关注点分离 33 2.3.5 明确分工 33 2.3.6 可移植性:Java、.NET及其他 33 2.3.7 开源和诚实 33 2.4 何时不该使用iBATIS 34 2.4.1 当永远拥有完全控制权时 34 2.4.2 当应用程序需要完全动态的SQL时 34 2.4.3 当没有使用关系数据库时 35 2.4.4 当iBATIS不起作用时 35 2.5 5分钟内用iBATIS创建应用程序 35 2.5.1 安装数据库 36 2.5.2 编写代码 36 2.5.3 配置iBATIS(预览) 37 2.5.4 构建应用程序 38 2.5.5 运行应用程序 39 2.6 iBATIS未来的发展方向 40 2.6.1 Apache软件基金会 40 2.6.2 更简单、更小且依赖性更少 40 2.6.3 更多的扩展点和插件 41 2.6.4 支持更多的平台和语言 41 2.7 小结 41 第二部分 iBATIS基础知识 第3章 安装和配置iBATIS 44 3.1 获得一份iBATIS发布 45 3.1.1 二进制发布 45 3.1.2 从源代码构建 45 3.2 发布中包含的内容 47 3.3 依赖性 48 3.3.1 针对延迟加载的字节码增强 48 3.3.2 Jakarta Commons数据库连接池 49 3.3.3 分布式高速缓存 49 3.4 将iBATIS添加到应用程序中 49 3.4.1 在独立应用程序中使用iBATIS 50 3.4.2 在Web应用程序中使用iBATIS 50 3.5 iBATIS和JDBC 51 3.5.1 释放JDBC资源 51 3.5.2 SQL注入 51 3.5.3 降低复杂度 52 3.6 配置iBATIS(续) 53 3.6.1 SQL Map配置文件 54 3.6.2 properties元素 55 3.6.3 settings元素 56 3.6.4 typeAlias元素 58 3.6.5 transactionManager元素 60 3.6.6 typeHandler元素 61 3.6.7 sqlMap元素 61 3.7 小结 62 第4章 使用已映射语句 63 4.1 从基础开始 63 4.1.1 创建JavaBean 64 4.1.2 SqlMap API 66 4.1.3 已映射语句的类型 67 4.2 使用select已映射语句 70 4.2.1 使用内联参数(用#做占位符) 70 4.2.2 使用内联参数(用$做占位符) 71 4.2.3 SQL注入简介 72 4.2.4 自动结果映射 73 4.2.5 联结相关数据 74 4.3 映射参数 75 4.3.1 外部参数映射 75 4.3.2 再论内联参数映射 76 4.3.3 基本类型参数 78 4.3.4 JavaBean参数和Map参数 78 4.4 使用内联结果映射和显式结果映射 78 4.4.1 基本类型结果 79 4.4.2 JavaBean结果和Map结果 81 4.5 小结 81 第5章 执行非查询语句 82 5.1 更新数据的基本方法 82 5.1.1 用于非查询SQL语句的SqlMap API 82 5.1.2 非查询已映射语句 83 5.2 插入数据 84 5.2.1 使用内联参数映射 84 5.2.2 使用外部参数映射 85 5.2.3 自动生成的键 86 5.3 更新和删除数据 88 5.3.1 处理并发更新 88 5.3.2 更新或删除子记录 89 5.4 运行批量更新 90 5.5 使用存储过程 91 5.5.1 优缺点分析 92 5.5.2 IN、OUT和INOUT参数 93 5.6 小结 95 第6章 使用高级查询技术 96 6.1 在iBATIS中使用XML 96 6.1.1 XML参数 96 6.1.2 XML结果 98 6.2 用已映射语句关联对象 101 6.2.1 复杂集合 101 6.2.2 延迟加载 104 6.2.3 避免N+1查询问题 105 6.3 继承 107 6.4 其他用途 109 6.4.1 使用语句类型和DDL 109 6.4.2 处理超大型数据集 109 6.5 小结 115 第7章 事务 116 7.1 事务是什么 116 7.1.1 一个简单的银行转账示例 116 7.1.2 理解事务的特性 118 7.2 自动事务 120 7.3 局部事务 121 7.4 全局事务 122 7.4.1 使用主动或被动事务 123 7.4.2 开始、提交以及结束事务 124 7.4.3 我是否需要全局事务 124 7.5 定制事务 125 7.6 事务划界 126 7.6.1 将事务在表现层划界 128 7.6.2 将事务在持久层划界 128 7.6.3 将事务在业务逻辑层划界 128 7.7 小结 129 第8章 使用动态SQL 130 8.1 处理动态WHERE子句条件 130 8.2 熟悉动态标签 132 8.2.1 dynamic标签 134 8.2.2 二元标签 135 8.2.3 一元标签 136 8.2.4 参数标签 137 8.2.5 iterate标签 138 8.3 一个简单而完整的示例 139 8.3.1 定义如何检索和显示数据 140 8.3.2 确定将涉及哪些数据库结构 140 8.3.3 以静态格式编写SQL 141 8.3.4 将动态SQL标签应用到静态SQL上 141 8.4 高级动态SQL技术 142 8.4.1 定义结果数据 142 8.4.2 定义所需的输入 143 8.4.3 以静态格式编写SQL 144 8.4.4 将动态SQL标签应用到静态SQL上 145 8.5 动态SQL的其他替代方案 147 8.5.1 使用Java代码 147 8.5.2 使用存储过程 150 8.5.3 同iBATIS相比较 152 8.6 动态SQL的未来 152 8.6.1 简化的条件标签 152 8.6.2 表达式语言 153 8.7 小结 153 第三部分 真实世界中的iBATIS 第9章 使用高速缓存提高性能 156 9.1 一个简单的iBATIS高速缓存示例 156 9.2 iBATIS高速缓存的理念 157 9.3 理解高速缓存模型 158 9.3.1 type属性 158 9.3.2 readOnly属性 159 9.3.3 serialize属性 159 9.3.4 联合使用readOnly属性和serialize属性 159 9.4 如何使用高速缓存模型中的标签 160 9.4.1 高速缓存的清除 160 9.4.2 设置高速缓存模型实现的特性 163 9.5 高速缓存模型的类型 163 9.5.1 MEMORY 163 9.5.2 LRU 164 9.5.3 FIFO 165 9.5.4 OSCACHE 166 9.5.5 你自己的高速缓存模型 166 9.6 确定高速缓存策略 166 9.6.1 高速缓存只读的长效数据 167 9.6.2 高速缓存可读写数据 169 9.6.3 高速缓存旧的静态数据 170 9.7 小结 172 第10章 iBATIS数据访问对象 173 10.1 隐藏实现细节 173 10.1.1 为何要分离 174 10.1.2 一个简单示例 175 10.2 配置DAO 177 10.2.1 properties元素 177 10.2.2 context元素 178 10.2.3 transactionManager元素 178 10.2.4 DAO元素 182 10.3 配置技巧 183 10.3.1 多个服务器 183 10.3.2 多种数据库方言 184 10.3.3 运行时配置更改 185 10.4 基于SQL Map的DAO实现示例 185 10.4.1 配置iBATIS DAO 186 10.4.2 创建DaoManager实例 187 10.4.3 定义事务管理器 187 10.4.4 加载映射 188 10.4.5 DAO实现编码 191 10.5 小结 193 第11章 DAO使用进阶 194 11.1 不是基于SQLMap的DAO实现 194 11.1.1 Hibernate版本的DAO实现 194 11.1.2 JDBC版本的DAO实现 199 11.2 为其他数据源使用DAO模式 203 11.2.1 示例:为LDAP使用DAO 203 11.2.2 示例:为Web服务使用DAO 208 11.3 使用Spring DAO 209 11.3.1 编写代码 209 11.3.2 为什么使用Spring代替iBATIS 211 11.4 创建自己的DAO层 211 11.4.1 从实现中分离出接口 212 11.4.2 创建一个工厂以解耦 212 11.5 小结 214 第12章 扩展iBATIS 215 12.1 理解可插拔组件的设计 215 12.2 使用自定义类型处理器 217 12.2.1 实现自定义类型处理器 217 12.2.2 创建TypeHandlerCallback 218 12.2.3 注册TypeHandlerCallback以供使用 221 12.3 使用CacheController 222 12.3.1 创建CacheController 223 12.3.2 CacheController的放入、获取以及清除操作 223 12.3.3 注册CacheController以供使用 224 12.4 配置iBATIS不支持的DataSource 224 12.5 定制事务管理 225 12.5.1 理解TransactionConfig接口 226 12.5.2 理解Transaction接口 227 12.6 小结 228 第四部分 iBATIS使用秘诀 第13章 iBATIS最佳实践 230 13.1 iBATIS中的单元测试 230 13.1.1 对映射层进行单元测试 231 13.1.2 对DAO进行单元测试 233 13.1.3 对DAO的消费层进行单元测试 235 13.2 管理iBATIS配置文件 237 13.2.1 将其保存在类路径上 237 13.2.2 集中放置文件 238 13.2.3 主要按返回类型来组织映射文件 239 13.3 命名规范 239 13.3.1 语句的命名 239 13.3.2 参数映射的命名 239 13.3.3 结果映射的命名 240 13.3.4 XML文件的命名 240 13.4 Bean、map还是XML 240 13.4.1 JavaBean 241 13.4.2 Map 241 13.4.3 XML 241 13.4.4 基本类型 241 13.5 小结 241 第14章 综合案例研究 243 14.1 设计理念 243 14.1.1 账户 243 14.1.2 目录 244 14.1.3 购物车 244 14.1.4 订单 244 14.2 选择具体的实现技术 244 14.2.1 表现层 244 14.2.2 服务层 244 14.2.3 持久层 245 14.3 调整Struts:使用BeanAction 245 14.3.1 BaseBean 246 14.3.2 BeanAction 246 14.3.3 ActionContext 246 14.4 JGameStore工程结构 247 14.4.1 src文件夹 247 14.4.2 test文件夹 248 14.4.3 web文件夹 248 14.4.4 build文件夹 248 14.4.5 devlib文件夹 248 14.4.6 lib文件夹 249 14.5 配置web.xml文件 249 14.6 设置表现层 251 14.6.1 第一步 251 14.6.2 使用表现层bean 253 14.7 编写服务层代码 257 14.7.1 配置dao.xml文件 258 14.7.2 事务划界 259 14.8 编写DAO 260 14.8.1 SQLMap配置 260 14.8.2 SQLMap文件 261 14.8.3 接口和实现 262 14.9 小结 263 附录A iBATIS.NET快速入门 264 A.1 比较iBATIS和iBATIS.NET 264 A.1.1 为何Java开发人员应该关心iBATIS.NET 264 A.1.2 为何.NET开发人员应该关心iBATIS.NET 265 A.1.3 主要区别是什么 265 A.1.4 相似之处又在哪里 265 A.2 使用iBATIS.NET 265 A.2.1 DLL和依赖性 265 A.2.2 XML配置文件 266 A.2.3 配置API 267 A.2.4 SQL映射文件 267 A.3 到哪里去查找更多的信息 269

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雨夜※繁华

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值