目的:将.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);
}
}
}
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();
}
大字节数据如图片、视频等。代码过程与1类似。主要是操作的数据类型变了。MySQL里边用的数据类型为:二进制字符串有 BIT、BINARY、VARBINARY、TINYBLOB、BLOB、MEDIUMBLOB 和 LONGBLOB。
而且对应的I/O流改为字节流。
三层架构介绍:百度百科-三层架构详解
三层架构就是为了符合“高内聚,低耦合”思想,把各个功能模块划分为表示层(UI)、业务逻辑层(BLL)和数据访问层(DAL)三层架构,各层之间采用接口相互访问
,并通过对象模型的实体类(Model)作为数据传递的载体,不同的对象模型的实体类一般对应于数据库的不同表,实体类的属性与数据库表的字段名一致。
三层架构区分层次的目的是为了 “高内聚,低耦合”。开发人员分工更明确,将精力更专注于应用系统核心业务逻辑的分析、设计和开发,加快项目的进度,提高了开发效率,有利于项目的更新和维护工作。
表示层
表示层又称表现层 UI,位于三层构架的最上层,与用户直接接触,主要是 B/S 信息系统中的 Wed 浏览页面。作为 Wed 浏览页面,表示层的主要功能是实现系统数据的传入与输出,在此过程中不需要借助逻辑判断操作就可以将数据传送到 BBL 系统中进行数据处理,处理后会将处理结果反馈到表示层中。换句话说,表示层就是实现用户界面功能,将用户的需求传达和反馈,并用 BLL 或者是 Models 进行调试,保证用户体验。
业务逻辑层
业务逻辑层 BLL 的功能是对具体问题进行逻辑判断与执行操作,接收到表现层 UI 的用户指令后,会连接数据访问层 DAL,访问层在三层构架中位于表示层与数据层中间位置,同时也是表示层与数据层的桥梁,实现三层之间的数据连接和指令传达,可以对接收数据进行逻辑处理,实现数据的修改、获取、删除等功能,并将处理结果反馈到表示层 UI 中,实现软件功能。
数据访问层 DAL
数据访问层 DAL是数据库的主要操控系统,实现数据的增加、删除、修改、查询等操作,并将操作结果反馈到业务逻辑层 BBL。在实际运行的过程中,数据访问层没有逻辑判断能力,为了实现代码编写的严谨性,提高代码阅读程度,一般软件开发人员会在该层中编写 Data AccessCommon,保证数据访问层 DAL 数据处理功能。
定义
DAO模式实际上是两个模式的组合,即Data Accessor (数据访问者)模式和 Active Domain Object(领域对象)模式。Data Accessor 模式实现了数据访问和业务逻辑的分离;Active Domain Object 模式实现了业务数据的对象化封装。
需要注意的是,DAO设计模式是Java EE中的设计模式,而非Java SE中的23种设计模式。
场景与需求
在Java程序中,经常需要把数据持久化,也需要获取持久化的数据,但是在进行数据持久化的过程中面临诸多问题(如:数据源不同、存储类型不同、供应商不同、访问方式不同等等),请问如何能以统一的接口进行数据持久化的操作?
把jdbc的操作进行分离,即数据库的操作和业务进行分离,javabean是把视图和业务进行分离,dao是把数据库的操作和业务逻辑进行分离.
DAO的组成部分
一个典型的DAO实现有下列几个组件:
三层模型中DAO的作用
DAO在三层结构模式中起来很大的作用,表现层通过逻辑层调用DAO,然后让DAO去调用数据层,这样很好的将数据层和其他两层隔离开,安全性和可维护性更高。然后在逻辑层和DAO层有可以建立新的DAO2,这个DAO2的作用就是避免外界直接接触里面的接口,主要通过工厂方法,实现接口的应用,这样的目的也是为了提高安全性,而且显得更层次感。
参考博客
DAO设计模式的【详解】及常见设计模式的【应用】
DAO设计模式
MySQL数据库学习笔记(十一)
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.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");
这个时候,我们只要把配置文件与工厂类的文件放在一起,无论位置变不变,都能使得代码正常运行。