JDBC实战(二)使用JDBC操作数据及DAO设计模式浅学

使用JDBC操作数据

1、使用JDBC将大文本数据写入数据库

目的:将.java等文本文件利用JDBC连接数据库写入到对应的表对应字段。
1、表结构
在这里插入图片描述
2、文件
在这里插入图片描述

3、插入文本的实现代码

package LoadFileTest;

import driver.JDBCUtils;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * 使用JDBC将文本文件插入到数据库并读取出来
 * 文件:Text_Test.java 类型文本类型
 * 使用的数据库数据类型为:Text
 * 涉及:I/O流操作
 */
public class Text_Test {
    public static void main(String[]args){
        insert_Text();
    }
    private static void insert_Text() {
        Connection conn =null;
        PreparedStatement ps = null;
        ResultSet re = null;
        try{
            conn = JDBCUtils.getConnect();
            System.out.println("connect database ....");
            String sql = "insert into big_text(Big_text) Values(?)";
            ps = conn.prepareStatement(sql);
            File f = new File("src/LoadFileTest/Text_Test.java");//创建文件对象
            BufferedReader bufferedReader = new BufferedReader(new FileReader(f));//装饰流
            ps.setCharacterStream(1,bufferedReader,f.length());//读取
            ps.executeUpdate();
            System.out.println("insert successfully!");
        } catch (SQLException | FileNotFoundException e) {
            e.printStackTrace();
        }finally {
            JDBCUtils.free(conn,ps,re);
        }
    }
}

4、运行结果
在这里插入图片描述

5、读取文本并保存到E盘、实现代码

private static void read_Text() {
        Connection conn =null;
        Statement st = null;
        ResultSet re = null;
        try{

            conn = JDBCUtils.getConnect();
            System.out.println("connect database ....");
            String sql = "select big_text from big_text where id=1";
            st = conn.createStatement();
            re = st.executeQuery(sql);
            File f = new File("E:\\Text_Test_bak.java");//保存的文件对象
            BufferedReader bf;
            BufferedWriter bw = new BufferedWriter(new FileWriter(f));
            while(re.next()){
                bf = new BufferedReader(re.getCharacterStream("big_text"));
                String buff;
                while((buff=bf.readLine())!=null){
                    bw.write(buff);
                    bw.newLine();
                }
                bw.close();//刷新
                bf.close();
            }
            System.out.println("read successfully!");

        } catch (SQLException | IOException e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.free(conn,st,re);
        }
    }

在这里插入图片描述

小结:
不同数据库的大文本类型不一样,我们需要懂得变通。MySQL的文本数据类型。MySQL 中的字符串类型有 CHAR、VARCHAR、TINYTEXT、TEXT、MEDIUMTEXT、LONGTEXT、ENUM、SET 等。
在这里插入图片描述
同时学习方法:setCharacterStream(),getCharacterStream()
三种读取结果集(文本类型数据)

 while(re.next()){
                //String s = re.getString("big_test");//这种方法也行
               // 这种也行
               /*Clob clob =  re.getClob(1);//获取第一列数据
               bf = new BufferedReader( clob.getCharacterStream());*/
                bf = new BufferedReader(re.getCharacterStream("big_text"));
                String buff;
                while((buff=bf.readLine())!=null){
                    bw.write(buff);
                    bw.newLine();
                }
                bw.close();
                bf.close();
            }

2、使用JDBC将大字节数据写入数据库

大字节数据如图片、视频等。代码过程与1类似。主要是操作的数据类型变了。MySQL里边用的数据类型为:二进制字符串有 BIT、BINARY、VARBINARY、TINYBLOB、BLOB、MEDIUMBLOB 和 LONGBLOB。
在这里插入图片描述
而且对应的I/O流改为字节流。

3、JDBC的使用和DAO设计思想

3.1、三层架构

三层架构介绍:百度百科-三层架构详解
三层架构就是为了符合“高内聚,低耦合”思想,把各个功能模块划分为表示层(UI)、业务逻辑层(BLL)和数据访问层(DAL)三层架构,各层之间采用接口相互访问,并通过对象模型的实体类(Model)作为数据传递的载体,不同的对象模型的实体类一般对应于数据库的不同表,实体类的属性与数据库表的字段名一致。

三层架构区分层次的目的是为了 “高内聚,低耦合”。开发人员分工更明确,将精力更专注于应用系统核心业务逻辑的分析、设计和开发,加快项目的进度,提高了开发效率,有利于项目的更新和维护工作。
在这里插入图片描述

表示层
表示层又称表现层 UI,位于三层构架的最上层,与用户直接接触,主要是 B/S 信息系统中的 Wed 浏览页面。作为 Wed 浏览页面,表示层的主要功能是实现系统数据的传入与输出,在此过程中不需要借助逻辑判断操作就可以将数据传送到 BBL 系统中进行数据处理,处理后会将处理结果反馈到表示层中。换句话说,表示层就是实现用户界面功能,将用户的需求传达和反馈,并用 BLL 或者是 Models 进行调试,保证用户体验。

业务逻辑层
业务逻辑层 BLL 的功能是对具体问题进行逻辑判断与执行操作,接收到表现层 UI 的用户指令后,会连接数据访问层 DAL,访问层在三层构架中位于表示层与数据层中间位置,同时也是表示层与数据层的桥梁,实现三层之间的数据连接和指令传达,可以对接收数据进行逻辑处理,实现数据的修改、获取、删除等功能,并将处理结果反馈到表示层 UI 中,实现软件功能。

数据访问层 DAL
数据访问层 DAL是数据库的主要操控系统,实现数据的增加、删除、修改、查询等操作,并将操作结果反馈到业务逻辑层 BBL。在实际运行的过程中,数据访问层没有逻辑判断能力,为了实现代码编写的严谨性,提高代码阅读程度,一般软件开发人员会在该层中编写 Data AccessCommon,保证数据访问层 DAL 数据处理功能。

3.2、DAO设计模式(Data Access Object、数据访问接口)

定义
DAO模式实际上是两个模式的组合,即Data Accessor (数据访问者)模式和 Active Domain Object(领域对象)模式。Data Accessor 模式实现了数据访问和业务逻辑的分离;Active Domain Object 模式实现了业务数据的对象化封装。

需要注意的是,DAO设计模式是Java EE中的设计模式,而非Java SE中的23种设计模式。

场景与需求
在Java程序中,经常需要把数据持久化,也需要获取持久化的数据,但是在进行数据持久化的过程中面临诸多问题(如:数据源不同、存储类型不同、供应商不同、访问方式不同等等),请问如何能以统一的接口进行数据持久化的操作?

解决办法
在这里插入图片描述

把jdbc的操作进行分离,即数据库的操作和业务进行分离,javabean是把视图和业务进行分离,dao是把数据库的操作和业务逻辑进行分离.

DAO的组成部分
一个典型的DAO实现有下列几个组件:

  • 1、DAO接口
    一个DAO接口;定义操作的接口,用于声明数据库的原子化操作,增删查改
  • 2、Imple
    一个实现DAO接口的具体类; 真实实现DAO接口的函数,只是单纯的处理数据。
  • 3、DTO
    数据传递对象(DTO):有些时候叫做值对象(VO)或领域模型(domain),对应数据库的表数据,VO(Value Object):就是存放项目中的一些要对其操作的数据类。
  • 4、Proxy
    代理实现类,通过代理类,用来调用真实的对象的操作
  • 5、Factory
    DAOFactory:工厂类,含有getInstance()创建一个DAOImpl类
    在这里插入图片描述

三层模型中DAO的作用
DAO在三层结构模式中起来很大的作用,表现层通过逻辑层调用DAO,然后让DAO去调用数据层,这样很好的将数据层和其他两层隔离开,安全性和可维护性更高。然后在逻辑层和DAO层有可以建立新的DAO2,这个DAO2的作用就是避免外界直接接触里面的接口,主要通过工厂方法,实现接口的应用,这样的目的也是为了提高安全性,而且显得更层次感。

  • 1、DAO其实是利用组合工厂模式来解决问题的,并没有带来新的功能,所以学的其实就是个思路。
  • 2、DAO理论上是没有层数限制的。
  • 3、DAO的各层理论上是没有先后的。

参考博客
DAO设计模式的【详解】及常见设计模式的【应用】
DAO设计模式
MySQL数据库学习笔记(十一)

3.3、基于DAO设计思想完成整个DAO的测试代码实现

1)首先设计的数据库——银行,拥有字段:id,姓名name,财富money
在这里插入图片描述

2)创建对应的包,结构如下:
在这里插入图片描述
3)先创建User类,即DTO

package DAO_design.user;

/**
 * 建立数据类对应数据库中某张表的字段
 * 数据传递对象(DTO)
 */

public class User {
    private int id;
    private String name;
    private float money;

    public User() {
    }

    public float getMoney() {
        return money;
    }

    public void setMoney(float money) {
        this.money = money;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "User [id=" + id + ", username=" + name + ", money=" + money + "]";
    }
}

4)然后创建DAO接口

package DAO_design.DAO;

import DAO_design.user.User;

/**
 * DAO接口
 */
public interface Dao {
    void addUser(User user);//添加user
    void deleteUser(String userName);//删除user
    void updateUser(User user);//更新user信息
    User findUser(String userName);//查询user
    boolean toUser(User user,User toUser,float money);//转账业务
}

5)再创建DAOImpl,实现接口

package DAO_design.DAOImpl;

import DAO_design.DAO.Dao;
import DAO_design.DAO.DaoException;
import DAO_design.user.User;
import driver.JDBCUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * 接口实现类,真实实现DAO接口的函数,只是单纯的处理数据。
 */

public class DaoImpl implements Dao {
    private User user;
    @Override
    public void addUser(User user) {
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try{
            conn = JDBCUtils.getConnect();
            String sql = "insert into bank(name,money) Values(?,?)";
            ps = conn.prepareStatement(sql);
            ps.setString(1,user.getName());
            ps.setFloat(2,user.getMoney());
            ps.executeUpdate();
        } catch (SQLException e) {
           throw new DaoException(e.getMessage());//千万不能随便打印堆栈跟踪或者抛出编译时异常
            //不利于将来的换其他数据库或者要修改各个接口。不知道那里出了问题。
        }finally {
            JDBCUtils.free(conn,ps,rs);
        }

    }

    @Override
    public void deleteUser(String userName) {
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try{
            conn = JDBCUtils.getConnect();
            String sql = "delete from bank where name=?";
            ps = conn.prepareStatement(sql);
            ps.setString(1,userName);
            ps.executeUpdate();
        } catch (SQLException e) {
            throw new DaoException(e.getMessage());//千万不能随便打印堆栈跟踪或者抛出编译时异常
            //不利于将来的换其他数据库或者要修改各个接口。不知道那里出了问题。
        }finally {
            JDBCUtils.free(conn,ps,rs);
        }

    }

    @Override
    public void updateUser(User user) {
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try{
            conn = JDBCUtils.getConnect();//JDBCUtils为之前创建的优化驱动注册和资源释放的工具类
            String sql = "update bank set money=? where name=?";
            ps = conn.prepareStatement(sql);
            ps.setFloat(1,user.getMoney());
            ps.setString(2,user.getName());
            ps.executeUpdate();
        } catch (SQLException e) {
            throw new DaoException(e.getMessage());//千万不能随便打印堆栈跟踪或者抛出编译时异常
            //不利于将来的换其他数据库或者要修改各个接口。不知道那里出了问题。
        }finally {
            JDBCUtils.free(conn,ps,rs);
        }
    }

    @Override
    public User findUser(String userName) {
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try{
            conn = JDBCUtils.getConnect();
            String sql = "select * from bank where name=?";
            ps = conn.prepareStatement(sql);
            ps.setString(1,userName);
            rs = ps.executeQuery();
            while(rs.next()){
                user = new User();
                user.setId(rs.getInt("id"));
                user.setMoney(rs.getFloat("money"));
                user.setName(rs.getString("name"));
            }
            return user;
        } catch (SQLException e) {
            throw new DaoException(e.getMessage());//千万不能随便打印堆栈跟踪或者抛出编译时异常
            //不利于将来的换其他数据库或者要修改各个接口。不知道那里出了问题。
        }finally {
            JDBCUtils.free(conn,ps,rs);
        }

    }

    @Override
    public boolean toUser(User user,User toUser,float money) {
        if(money>0.0001){
            user.setMoney(user.getMoney()-money);
            toUser.setMoney(toUser.getMoney()+money);
            updateUser(user);
            updateUser(toUser);
            return true;
        }else
            throw new RuntimeException("转账金额不能为负数!");
    }
}

5)创建自定义运行时异常DaoException

package DAO_design.DAO;

/**
 * DAO设计模式如何处理异常,不要只打印或者抛出编译时异常,影响日后的维护
 */
public class DaoException extends RuntimeException {
    public DaoException(Throwable cause) {
        super(cause);
    }

    protected DaoException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }

    public DaoException(String message) {
        super(message);
    }

    public DaoException(String message, Throwable cause) {
        super(message, cause);
    }

    public DaoException() {
        super();
    }
}

6)最后创建工厂类DaoFactory

package DAO_design.Factory;

import DAO_design.DAOImpl.DaoImpl;

/**
 * 创建工厂类,用于生产DAO接口实例
 */
public class DaoFactory {
    public static DaoImpl getDaoImp(){
        return new DaoImpl();
    }
}

测试代码

package DAO_design.Test;

import DAO_design.DAOImpl.DaoImpl;
import DAO_design.Factory.DaoFactory;
import DAO_design.user.User;

public class DaoTest {
    public static void main(String[]args){
        User user = new User();
        user.setName("王二小");
        user.setMoney(1000.0f);
        System.out.println(user.toString());
        DaoImpl daoImpl = DaoFactory.getDaoImp();
        //插入数据
        User toUser = new User();
        toUser.setName("小肥仔");
        toUser.setMoney(1000000);
        //王二小给小肥仔转100块
        daoImpl.toUser(user,toUser,100);//
        //daoImpl.updateUser(user);
       // daoImpl.deleteUser("王二小");
        //User finuser = daoImpl.findUser("王二小");
       // System.out.println(finuser.toString());

    }
}

添加user

  User user = new User();
  user.setName("王二小");
user.setMoney(1000.0f);
System.out.println(user.toString());
DaoImpl daoImpl = DaoFactory.getDaoImp();
//插入数据
daoImpl.addUser(user);

在这里插入图片描述

删除user

daoImpl.deleteUser("王二小");

在这里插入图片描述

3.4、优化工厂模式代码实现

3.3中,代码较为不足的地方

在这里插入图片描述

优化,使用配置文件的形式,根据文件的键值对,来创建对应的DAOImpl

1)先创建配置文件(注意字节码文件的位置往往在out目录,可以通过File——Project Structure——Modules——Path查看,配置文件需要用包名.来访问)
在这里插入图片描述

2)修改工厂类的代码

package DAO_design.Factory;

import DAO_design.DAO.Dao;//统一接口

import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.util.Properties;

/**
 * 创建工厂类,用于生产DAO接口实例
 */
public class DaoFactory {
    private static Dao daoImpl = null;
    private static DaoFactory daoFactory = null;//单例懒汉式,也可以通过静态代码块

    private DaoFactory() {
        try {
            InputStream inputs = new FileInputStream(new File("src/DAO_design/DAOImpl.properties"));
            Properties properties = new Properties();
            properties.load(inputs);
            String DaoImplClass = properties.getProperty("DaoImplClass");

            //创建实例
            //daoImpl = Class.forName(DaoImplClass).newInstance();//过时方法
            //替代方案
            Class<?> clazz = Class.forName(DaoImplClass);
            daoImpl = (Dao) clazz.getDeclaredConstructor().newInstance();
        } catch (IllegalAccessException | InstantiationException |
                InvocationTargetException | ClassNotFoundException | NoSuchMethodException | IOException e) {
            e.printStackTrace();
        }
    }
    public static DaoFactory getDaoFactory() {
        if (daoFactory == null) {
            synchronized (DaoFactory.class) {
                if (daoFactory == null)
                    daoFactory = new DaoFactory();
            }
        }
        return daoFactory;
    }
    public static Dao getInstance(){
        return  daoImpl;
    }
}

3)修改测试代码,测试如下:

package DAO_design.Test;

import DAO_design.DAO.Dao;//不用导入具体的实现接口,减少依赖
import DAO_design.Factory.DaoFactory;
import DAO_design.user.User;

public class DaoTest {
    public static void main(String[]args){
        User user = new User();
        user.setName("王小");
        user.setMoney(1000.0f);
        System.out.println(user.toString());
        Dao daoImpl = DaoFactory.getDaoFactory().getInstance();
        daoImpl.addUser(user);
        //插入数据
        User toUser = new User();
        toUser.setName("淡仔");
        toUser.setMoney(10000);
        daoImpl.addUser(toUser);


    }
}

在这里插入图片描述

思考:当配置文件位置发生了变动?那就要修改代码中配置文件的位置,解决办法如下:

 //InputStream inputs = new FileInputStream(new File("src/DAO_design/DAOImpl.properties"));
InputStream inputs = DaoFactory.class.getClassLoader().getResourceAsStream("Dao_config.properties");

这个时候,我们只要把配置文件与工厂类的文件放在一起,无论位置变不变,都能使得代码正常运行。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

雨夜※繁华

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

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

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

打赏作者

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

抵扣说明:

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

余额充值