Java JDBC相关个人学习分享

[TOC]

# 反射

> 是Java高级中必须掌握的技术

## Class类型

当我们执行一个Java的源文件时,会把该源文件翻译成字节码文件(class),再由JVM里的解释器进行解释执行.在解释的时候需要通过类加载(ClassLoader)把上面的class文件加载到内存中.

在这个class运行的过程中,它的所有信息(有哪些字段,有哪些方法.类名等)我们把它们叫做RTTI(Run-Time Type Identification 运行时类型信息).这些信息被封装在一个Class对象中.

## Class的获取方式

常用的有三种获取方式

```java
/**
 *
 */
package com.hwua.demo;

/**
 * @ClassName: Demo01
 * @Description:TODO(这里用一句话描述这个类的作用)
 * @author: Administrator
 * @date: 2019年4月19日 上午9:21:37
 * 
 * @Copyright: 2019 www.hwua.com Inc. All rights reserved.
 * 
 */
public class Demo01 {

    public static void main(String[] args) {

        try {
            // -- 第一种方式
            Class<?> clz1 = Class.forName("java.util.Scanner");
            Demo01 d = new Demo01();

            // -- 第二种方式 对象.getClass();
            Class<? extends Demo01> clz2 = d.getClass();

            // -- 第三种方式 类名.class
            Class clz3 = Demo01.class;

        } catch (ClassNotFoundException e) {
            // -- 过程中会产生类找不到异常
            e.printStackTrace();
        }
    }
}
```

## 通过Class对象获取运行时类型信息

### 获取对象

在Java中用于创建对象的方式有5种

* 使用new + 构造方法创建
* 使用反射创建(有两套写法)
* 使用反序列化
* 使用克隆创建

```java
/**
 *
 */
package com.hwua.demo;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Scanner;

/**
 * @ClassName: Demo02
 * @Description:TODO(这里用一句话描述这个类的作用)
 * @author: Administrator
 * @date: 2019年4月19日 上午9:27:27
 * 
 * @Copyright: 2019 www.hwua.com Inc. All rights reserved.
 * 
 */
public class Demo02 {
    public static void main(String[] args) {
        try {
            // -- 加载java.util.Scanner到内存.
            Class<?> clz = Class.forName("com.hwua.demo.Student");
            // -- 通过Class对象来构造Student的对象.是利用无参构造方法.如果没有无参会报错!
            // -- 利用构造方法对象构造对象
            Object obj = clz.newInstance();
            // -- 判断obj对象的真实类型是否是Scanner类型
            if (obj instanceof Student) {
                Student stu = (Student) obj;
                stu.setSage(18);
                stu.setSid(1);
                stu.setSname("张三");
                System.out.println(stu);
            }
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
```

### 获取字段

#### 调用字段的Set方法

```JAVA
/**
 *
 */
package com.hwua.demo02;

import java.lang.reflect.Field;

/**
 * @ClassName: Demo01
 * @Description: 测试获取字段和调用字段的set方法
 * @author: Administrator
 * @date: 2019年4月19日 上午10:49:16
 * 
 * @Copyright: 2019 www.hwua.com Inc. All rights reserved.
 * 
 */
public class Demo01 {

    public static void main(String[] args) {

        // -- 1.获取Class对象
        Class<?> clz = Dog.class;

        // -- 2.通过Class对象获取所有的字段信息
        /*
         * Field 成员变量 字段 Local Variable 局部变量 Param 方法参数 Constant 常量 getFields()
         * 获取的是都是非私有的字段
         */
        // Field[] fields = clz.getFields();
        // -- 可以获取私有的字段
        Field[] fields = clz.getDeclaredFields();

        Dog dog = null;
        try {
            dog = (Dog) clz.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        // -- 3.遍历数组
        for (int i = 0; i < fields.length; i++) {
            Field f = fields[i];
            // -- 私有的设置可见.不然无法访问
            f.setAccessible(true);
            if (f.getName().equalsIgnoreCase("age")) {
                try {
                    f.set(dog, 18);
                } catch (IllegalArgumentException | IllegalAccessException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }

            if (f.getName().equalsIgnoreCase("name")) {
                try {
                    f.set(dog, "旺财");
                } catch (IllegalArgumentException | IllegalAccessException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }

            if (f.getName().equalsIgnoreCase("color")) {
                try {
                    f.set(dog, "七彩斑斓");
                } catch (IllegalArgumentException | IllegalAccessException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
        System.out.println(dog);
    }
}
```

# 工厂设计模式

## 工厂设计模式的作用

简单说就是帮我们创建对象.

## 为什么使用工厂

解耦合.我们所期望的软件是高内聚低耦合的.一个应用由N个模块组成.这N个模块的关联程度尽量降低.最好做到中间某个模块的移除,其它模块不受影响.热插拔.

假设有类A和类B.

```java
class A{
    B b;
    A(){
      b = new B();  
    }  
}
class B{}
```

如上所示,A的实例化是依赖B的实例化.如果B的对象构建失败A的构造方法结束执行.所以A的对象也没有创建成功!所以A是依赖于B的.

现在我们需要改变A和B的依赖关系.把B的创建交给工厂.A只需要接收工厂返回的对象就可以了.

这样就降低了A和B之间的依赖关系.

## 工厂的实现

> ​    简单工厂/静态工厂

### Switch Case的写法

```java
/**
 *
 */
package com.hwua.demo02;

/**
 * @ClassName: Animal
 * @Description:TODO(这里用一句话描述这个类的作用)
 * @author: Administrator
 * @date: 2019年4月19日 上午9:52:05
 * 
 * @Copyright: 2019 www.hwua.com Inc. All rights reserved.
 * 
 */
public class Animal {

    public void method() {
        System.out.println("This is animal");
    }
}
/**
 *
 */
package com.hwua.demo02;

/**
 * @ClassName: Dog
 * @Description:TODO(这里用一句话描述这个类的作用)
 * @author: Administrator
 * @date: 2019年4月19日 上午9:52:09
 * 
 * @Copyright: 2019 www.hwua.com Inc. All rights reserved.
 * 
 */
public class Dog extends Animal {

    /**
     * <p>
     * Title: method
     * </p>
     * <p>
     * Description:
     * </p>
     * 
     * @see com.hwua.demo02.Animal#method()
     */
    @Override
    public void method() {
        System.out.println("This is dog");
    }
}
/**
 *
 */
package com.hwua.demo02;

/**
 * @ClassName: Cat
 * @Description:TODO(这里用一句话描述这个类的作用)
 * @author: Administrator
 * @date: 2019年4月19日 上午9:52:13
 * 
 * @Copyright: 2019 www.hwua.com Inc. All rights reserved.
 * 
 */
public class Cat extends Animal {

    /**
     * <p>
     * Title: method
     * </p>
     * <p>
     * Description:
     * </p>
     * 
     * @see com.hwua.demo02.Animal#method()
     */
    @Override
    public void method() {
        System.out.println("This is cat");
    }
}
/**
 *
 */
package com.hwua.demo02;

/**
 * @ClassName: Rabbit
 * @Description:TODO(这里用一句话描述这个类的作用)
 * @author: Administrator
 * @date: 2019年4月19日 上午9:52:17
 * 
 * @Copyright: 2019 www.hwua.com Inc. All rights reserved.
 * 
 */
public class Rabbit extends Animal {

    /**
     * <p>
     * Title: method
     * </p>
     * <p>
     * Description:
     * </p>
     * 
     * @see com.hwua.demo02.Animal#method()
     */
    @Override
    public void method() {
        System.out.println("This is rabbit");
    }
}
/**
 *
 */
package com.hwua.demo02;

/**
 * @ClassName: AnimalFactory
 * @Description:TODO(这里用一句话描述这个类的作用)
 * @author: Administrator
 * @date: 2019年4月19日 上午9:52:26
 * 
 * @Copyright: 2019 www.hwua.com Inc. All rights reserved.
 * 
 */
public class AnimalFactory {
    public static Animal getAnimal(String str) {
        Animal ai = null;

        switch (str) {
        case "animal":
            ai = new Animal();
            break;
        case "dog":
            System.out.println(1);
            ai = new Dog();
            break;
        case "cat":
            ai = new Cat();
            break;
        case "rabbit":
            ai = new Rabbit();
            break;
        default:
            ai = new Animal();
            break;
        }
        return ai;
    }
}
/**
 *
 */
package com.hwua.demo02;

/**
 * @ClassName: FactoryTest
 * @Description:TODO(这里用一句话描述这个类的作用)
 * @author: Administrator
 * @date: 2019年4月19日 上午9:55:40
 * 
 * @Copyright: 2019 www.hwua.com Inc. All rights reserved.
 * 
 */
public class FactoryTest {

    public static void main(String[] args) {
        Animal dog = AnimalFactory.getAnimal("rabbit");
        dog.method();
    }
}

```

### 反射的写法

#### SwitchCase写法的弊端

能够创建的对象一般都是存在继承关系的.并且由字符串来决定.不够方便和灵活

#### 反射+工厂

```java
/**
 *
 */
package com.hwua.demo02;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * @ClassName: AnimalFactory
 * @Description:  利用反射来实现实现工厂 
 * @author: Administrator
 * @date: 2019年4月19日 上午9:52:26
 * 
 * @Copyright: 2019 www.hwua.com Inc. All rights reserved.
 * 
 */
public class AnimalFactory2 {
    /**
     * f
     * @Title: getAnimal   
     * @Description: 利用传入的Class信息构建对象  
     * @param:  clz
     * @return: Object      
     * @throws
     */
    public static Object getInstance(Class<?> clz) {
        
        Object obj = null;
        try {
            //-- newIntance 本质:调用类中的无参构造
            obj = clz.newInstance();
        } catch (InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return obj;
    }
    
    /**
     * 
     * @Title: getInstance   
     * @Description: 根据类型信息和参数来构建对象.  
     * @param:  str 所要创建的对象的完整路径 包名.类名
     * @param:  parasm 构造方法的参数   
     * @return: Object  所构建的对象     
     * @throws
     */
    public static Object getInstance(String str,Object... parasm) {
        
        Object obj = null;
        try {
            Class<?> clz = Class.forName(str);
            //-- 利用clz获取构造方法
            Constructor<?> cons = clz.getConstructor(String.class);
            obj = cons.newInstance(parasm[0]);
            
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return obj;
    }
}

```

# 接口回调

## 回调概念

在开发中.方法的执行流程有三个方向

* 同步    

    > 方法A->方法B

* 异步

    > 方法A<-方法B

* 回调

    > 方法A->方法B->方法A

举一个很简单的例子.比如Boss安排员工办事,在员工执行完成后要告诉Boss工作完成了.

## 回调的代码实现

```java
/**
 *
 */
package com.hwua.demo03;

/**
 * @ClassName: CallBoss
 * @Description: 联系Boss的行为接口
 * @author: Administrator
 * @date: 2019年4月19日 下午1:39:46
 * 
 * @Copyright: 2019 www.hwua.com Inc. All rights reserved.
 * 
 */
public interface CallBoss {

    void callBoss();
}


/**
 *
 */
package com.hwua.demo03;

/**
 * @ClassName: Boss
 * @Description:TODO(这里用一句话描述这个类的作用)
 * @author: Administrator
 * @date: 2019年4月19日 下午1:36:03
 * 
 * @Copyright: 2019 www.hwua.com Inc. All rights reserved.
 * 
 */
public class Boss implements CallBoss {

    /**
     * 
     * @Title: orderEmployeeDo @Description: 老板安排员工干活! @param: e 要干活的员工 @return:
     * void @throws
     */
    public void orderEmployeeDo(Employee e) {
        System.out.println("Boss 下派任务");
        e.doSomething();
    }

    /**
     * <p>
     * Title: callBoss
     * </p>
     * <p>
     * Description:
     * </p>
     * 
     * @see com.hwua.demo03.CallBoss#callBoss()
     */
    @Override
    public void callBoss() {
        System.out.println("Boss 说我知道了!");
    }

}
/**
 *
 */
package com.hwua.demo03;

/**
 * @ClassName: Employee
 * @Description:TODO(这里用一句话描述这个类的作用)
 * @author: Administrator
 * @date: 2019年4月19日 下午1:36:14
 * 
 * @Copyright: 2019 www.hwua.com Inc. All rights reserved.
 * 
 */
public class Employee {

    /**
     * 提供成员变量. 类型是接口类型. 给员工提供联系老板的方式
     */
    private CallBoss cb;

    /**
     * @Title: setCb <BR>
     * @Description: please write your description <BR>
     * @return: CallBoss <BR>
     */
    public void setCb(CallBoss cb) {
        this.cb = cb;
    }

    /**
     * @Title: doSomething @Description: 员工干活 @param: @return: void @throws
     */
    public void doSomething() {
        for (int i = 0; i < 10; i++) {
            System.out.println("员工干活中!..");
        }
        // -- 通知老板活干完了
        cb.callBoss();
    }

}
/**
 *
 */
package com.hwua.demo03;

/**
 * @ClassName: Test
 * @Description:TODO(这里用一句话描述这个类的作用)
 * @author: Administrator
 * @date: 2019年4月19日 下午1:38:34
 * 
 * @Copyright: 2019 www.hwua.com Inc. All rights reserved.
 * 
 */
public class Test {
    public static void main(String[] args) {
        Boss b = new Boss();
        Employee e = new Employee();
        e.setCb(b);

        b.orderEmployeeDo(e);
    }

}
```

## 修改Dao类通过回调来实现对象的封装

我们在Dao中需要对数据库做操作.当我们执行查询的语句时,会发现都需要写一段类似的代码

```java
while(rSet.next()){
    对象.set(rSet.getString("字段名"));
}
```

当一个Dao中有10个查询方法时,上面的这段代码需要写10遍,如果有10实体类.那要写100遍.

这样会造成大量的代码重复.想要简化这一块的代码所以使用回调函数来修改Dao

```java
/**
 *
 */
package com.hwua.demo04;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

/**
 * @ClassName: ResultSetHandler
 * @Description:定义回调接口用于处理结果集
 * @author: Administrator
 * @date: 2019年4月19日 下午1:50:36
 * 
 * @Copyright: 2019 www.hwua.com Inc. All rights reserved.
 * 
 */
public interface ResultSetHandler<T> {

    public List<T> handler(ResultSet rSet) throws SQLException;

}
```

在Dao的实现类上.我们去实现这个回调接口,并实现处理结果集的方法.

```java
/**
 *
 */
package com.hwua.demo04;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ParameterMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/**
 * @ClassName: StuDaoImpl
 * @Description:TODO(这里用一句话描述这个类的作用)
 * @author: Administrator
 * @date: 2019年4月19日 下午1:50:19
 * 
 * @Copyright: 2019 www.hwua.com Inc. All rights reserved.
 * 
 */
public class StuDaoImpl implements ResultSetHandler<Stu> {

    /**
     * <p>
     * Title: handler
     * </p>
     * <p>
     * Description:
     * </p>
     * 
     * @param rSet
     * @return
     * @throws SQLException
     * @see com.hwua.demo04.ResultSetHandler#handler(java.sql.ResultSet)
     */
    @Override
    public List<Stu> handler(ResultSet rSet) throws SQLException {
        List<Stu> stuList = new ArrayList<Stu>();
        while (rSet.next()) {
            Stu stu = new Stu();
            stu.setSage(rSet.getInt("sage"));
            stu.setSname(rSet.getString("sname"));
            stu.setSgender(rSet.getString("sgender"));
            stu.setSid(rSet.getString("sid"));
            stuList.add(stu);
        }
        return stuList;
    }
}

```

再提供查询数据的方法.

```java
public List<Stu> listStus() throws ClassNotFoundException, SQLException {
    // -- 1.获取数据库连接
    Connection conn = DbTools.getConnection();
    // -- 2.提供SQL语句
    String sql = "select * from stu";
    // -- 3.通过连接获取PreparedStatement对象
    PreparedStatement statement = conn.prepareStatement(sql);
    // -- 4.替换占位符
    // -- 5.执行SQL语句得到结果集 .结果集是永远不会为null的.
    ResultSet rSet = statement.executeQuery();
    // -- 6.遍历结果集 .
    List<Stu> stuList = handler(rSet);
    // -- 7.关闭结果集,关闭PreparedStatement
    // -- 切记:关闭的顺序和开启的顺序正好相反!
    if (!rSet.isClosed()) {
        rSet.close();
    }
    if (statement != null || !statement.isClosed()) {
        statement.close();
    }
    return stuList;
}
```

# JDBC Template

在Dao的方法中可以发现增删改的基本流程是一致的.查询的流程是独立的.我们可以封装工具类来作为模板类

## 查询的模板方法

```java
//-- 1.提供回调接口
/**
 *
 */
package com.hwua.demo04;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

/**
 * @ClassName: ResultSetHandler
 * @Description:TODO(这里用一句话描述这个类的作用)
 * @author: Administrator
 * @date: 2019年4月19日 下午1:50:36
 * 
 * @Copyright: 2019 www.hwua.com Inc. All rights reserved.
 * 
 */
public interface ResultSetHandler<T> {

    public List<T> handler(ResultSet rSet) throws SQLException;

}


//-- 2.提供Dao实现类
/**
 *
 */
package com.hwua.demo04;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ParameterMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/**
 * @ClassName: StuDaoImpl
 * @Description:TODO(这里用一句话描述这个类的作用)
 * @author: Administrator
 * @date: 2019年4月19日 下午1:50:19
 * 
 * @Copyright: 2019 www.hwua.com Inc. All rights reserved.
 * 
 */
public class StuDaoImpl implements ResultSetHandler<Stu> {

    /**
     * <p>
     * Title: handler
     * </p>
     * <p>
     * Description:
     * </p>
     * 
     * @param rSet
     * @return
     * @throws SQLException
     * @see com.hwua.demo04.ResultSetHandler#handler(java.sql.ResultSet)
     */
    @Override
    public List<Stu> handler(ResultSet rSet) throws SQLException {
        List<Stu> stuList = new ArrayList<Stu>();
        while (rSet.next()) {
            Stu stu = new Stu();
            stu.setSage(rSet.getInt("sage"));
            stu.setSname(rSet.getString("sname"));
            stu.setSgender(rSet.getString("sgender"));
            stu.setSid(rSet.getString("sid"));
            stuList.add(stu);
        }
        return stuList;
    }

    /**
     * 
     *  @Title: findStu 通用的查询方法
     *  @Description: 根据条件查找学生
     *  @param: sql 要执行的sql语句 
     *  @param: params sql语句中的条件. 
     *  @return: Stu 所查找到的学生对象或者null 
     *  @throws SQLException 
     *  @throws ClassNotFoundException 
     */
    public List<Stu> findStu(String sql, Object... params) throws ClassNotFoundException, SQLException {
        // -- 1.拿连接
        Connection conn = DbTools.getConnection();
        // -- 2.预处理
        PreparedStatement statement = conn.prepareStatement(sql);
        // -- 3.先获取参数的元数据对象.
        ParameterMetaData metaData = statement.getParameterMetaData();
        // -- 4.通过元数据对象获取参数的数量
        int parameterCount = metaData.getParameterCount();
        // -- 5.循环遍历
        for (int i = 0; i < parameterCount; i++) {
            // -- 6.替换占位符 占位符的下标从1开始
            statement.setObject(i + 1, params[i]);
        }
        // -- 7.执行sql语句
        ResultSet set = statement.executeQuery();
        // -- 8.通过回调处理结果集
        List<Stu> stuList = handler(set);
        // -- 9.返回结果集
        return stuList;
    }
}

```

## 增删改的模板方法

```java
public int updateStu(String sql, Object... params) throws ClassNotFoundException, SQLException {
    // -- 1.拿连接
    Connection conn = DbTools.getConnection();
    // -- 2.预处理
    PreparedStatement statement = conn.prepareStatement(sql);
    // -- 3.先获取参数的元数据对象.
    ParameterMetaData metaData = statement.getParameterMetaData();
    // -- 4.通过元数据对象获取参数的数量
    int parameterCount = metaData.getParameterCount();
    // -- 5.循环遍历
    for (int i = 0; i < parameterCount; i++) {
        // -- 6.替换占位符 占位符的下标从1开始
        statement.setObject(i + 1, params[i]);
    }
    // -- 7.执行sql语句
    int columns = statement.executeUpdate();
    return columns;
}
```

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值