您当前的位置: 首页 >  oracle

止步前行

暂无认证

  • 0浏览

    0关注

    247博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

将大文件存到Oracle数据库

止步前行 发布时间:2019-08-09 10:35:47 ,浏览量:0

一、引言

先描述一下需求:

目前手中的项目是一个比较老的平台系统,一个单体应用,即所有的模块都打包在一个War包中发布到Tomcat。由于是国企单位的内网环境,公司没有独立的文件服务器,对于以前的老系统,文件的存储和访问,在一台服务器上,完全不是问题。

但现在要将老系统的各个模块抽取出来,做成各个独立的微服务。在这种情况下,文件的存储和访问就会有问题,一个节点的资源,如何让其他节点访问?由于我对客观环境不是很清楚,给的建议是提供一个公共的文件服务,但领导说,条件不允许。因为在项目实施的时候,每个省公司都是内网环境,难道要让每个省公司都搭建一个文件服务器?成本太高……

So,将文件存储数据库,就是讨论的结果。每次涉及文件上传,就将文件存到数据库,若其他节点发现自己本节点没有该文件,就去数据库中把文件拉去下来。用这种方法来实现文件共享存储。

这种方式我是排斥的,但条件所限,没有办法……

二、具体代码 1、几点说明

平台数据库:Oracle

数据库字段:file_content为存储文件的字段

在这里插入图片描述

2、代码实现
public class ResourceDao {

    private static final org.slf4j.Logger LOG = 
    				LoggerFactory.getLogger(ResourceDao.class);

    /**
     *  读取数据表中资源
     * @param fileSrcMd 文件路径的MD5值
     * @return boolean 读取成功/失败
     */
    public boolean readResourceFromDB(String fileSrcMd) {

        FileOutputStream fos = null;
        String fileSrc = "";
        InputStream in = null;

        try{
            //获得数据库连接
            Connection con = PoolManager.getPoolConnection();
            con.setAutoCommit(false);
            String querySql = "select file_src, file_content from " 
           		 + "t_file_content where file_src_md = ?";
            PreparedStatement ps = con.prepareStatement(querySql);
            ps.setString(1,fileSrcMd);
            ResultSet rs = ps.executeQuery();

            if (rs.next()) {
                fileSrc = rs.getString("file_src");
                java.sql.Blob blob = rs.getBlob("file_content");
                in = blob.getBinaryStream();
            } else {
                LOG.warn("no resource by md5: {}", fileSrcMd);
                return false;
            }

            File file = new File(fileSrc);
            if (!file.getParentFile().exists()) {
                boolean succ = file.getParentFile().mkdirs();
                if (!succ) {
                    throw new Exception("mkdir failed: " 
                    	+ file.getParentFile().getAbsolutePath());
                }
            }
            fos = new FileOutputStream(file);
            int len = 0;
            byte[] buf = new byte[1024];
            while ((len = in.read(buf)) != -1) {
                fos.write(buf, 0, len);
            }
            fos.flush();
            con.commit();
            return true;
        } catch (Exception e) {
            LOG.error("readResourceFromDB异常:", e);
            return false;
        } finally {
            LOG.debug("readResourceFromDB() enter finally");
            if (null != fos) {
                try {
                    fos.close();
                } catch (IOException e) {
                }
            }

            if (null != in) {
                try {
                    in.close();
                } catch (IOException e) {
                }
            }
        }
    }


    /**
     * 将资源保存到数据库中
     * @param fileTid  文件id
     * @param fileSrc 文件路径
     * @throws Exception
     */
    public void saveResourceToDB(String fileTid, String fileSrc) 
    		throws Exception {

        OutputStream os = null;
        FileInputStream fis = null;
        // 文件路径MD5值
        String fileSrcMd = Md5Tool.getMd5(fileSrc);
        try {
            //获得数据库连接
            Connection con = PoolManager.getPoolConnection();
            con.setAutoCommit(false);
            String sql = "insert into t_file_content (file_tid, file_src_md,"
            + "file_src,file_content) values (?, ?, ?, empty_blob())";
            PreparedStatement ps = con.prepareStatement(sql);
            ps.setString(1,fileTid);
            ps.setString(2,fileSrcMd);
            ps.setString(3,fileSrc);
            //插入一个空对象empty_blob()
            ps.executeUpdate();

            ps.close();
            //锁定数据行进行更新,用for update加锁
            String querySql = "select file_content from t_file_content "
            	+ "where file_src_md = ? for update";

            ps = con.prepareStatement(querySql);
            ps.setString(1,fileSrcMd);
            ResultSet rs = ps.executeQuery();
            File file = new File(fileSrc);
            if(!file.exists()) {
                return;
            }
            fis = new FileInputStream(file);
            byte[] buffer = new byte[1024];

            if (rs.next()) {
                //得到java.sql.Blob对象后强制转换为oracle.sql.BLOB
                oracle.sql.BLOB blob = (oracle.sql.BLOB) 
                				rs.getBlob("file_content");
                os = blob.getBinaryOutputStream();
                int len = 0;
                while ((len = fis.read(buffer)) != -1) {
                    os.write(buffer, 0, len);
                }
            }
            os.flush();
            con.commit();
        }catch (Exception e){
            LOG.error("saveResourceToDB异常:", e);
            throw e;
        }finally {
            LOG.debug("saveResourceToDB enter finally");
            if (null != os) {
                try {
                    os.close();
                } catch (IOException e) {
                }
            }
            if (null != fis) {
                try {
                    fis.close();
                } catch (IOException e) {
                }
            }
        }
    }


    /**
     *  解决资源文件生成相同的MD5值,导致数据库插入失败。
     *  解决办法:重新生成新的文件名,最多MD5碰撞3次。
     *  此处要把文件的绝对路径返回,要不然,t_media_cotent、t_file_content 中
     *  路径不一致
     * @param fileTid
     * @param fileSrc
     * @throws Exception
     */
    public String saveResourceToDBWithNoCollision(String fileTid, 
    	String fileSrc) throws Exception {
        String fileUUid = "";
        Exception saveResourceException = null;
        File file = new File(fileSrc);
        for (int i = 0; i  0){
                    renameDestFile = new File(fileDir + "/"+ fileName);
                }else{
                    renameDestFile = new File(fileDir + "\\" + fileName);
                }
                file.renameTo(renameDestFile);
                file = renameDestFile;
                continue;
            }
        }
        // 循环尝试插库3次不成功,抛出插库异常
        throw saveResourceException;
    }



//    public static Connection getConnection(){
//
//        Connection conn = null;
//        try {
//            Class.forName("oracle.jdbc.driver.OracleDriver");
//            String url="jdbc:oracle:thin:@192.168.200.124:1521:dev";
//            conn = DriverManager.getConnection(url,"aaa","111111 ");
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//        return conn;
//    }
//
//    //测试
//    public static void main(String[] args) {
//
//        ResourceDao dao = new ResourceDao();
//     入库
//        String fileTid = Utility.newUUID();
//        String fileSrc = "F:\\pic\\pic\\pc\\addr\\logo.png";
//        String fileSrcMd = Md5Tool.getMd5(fileSrc);
//
//        System.out.println("fileTid:"+fileTid);
//        System.out.println("fileSrc:"+fileSrc);
//        System.out.println("fileSrcMd:"+fileSrcMd);
//
//
//        try {
//            dao.saveResourceToDBWithNoCollision(fileTid,fileSrc);
            dao.saveResourceToDB(fileTid,fileSrc);
//        }catch (Exception e){
//            System.out.println("EMPException:" + e);
//        }


//     --------------------------------------------------
//     从库中取资源
//        String fileSrc = "F:\\pic\\pic\\pc\\addr\\logo.png";
//        String fileSrcMd = "9270d863bbbe6f13114fc9e2ce544c93";
//
//        System.out.println("fileSrc after md5 :" + Md5Tool.getMd5(fileSrc));
//        System.out.println("fileSrcMd  :" + fileSrcMd);
//
//        try {
//            dao.readResourceFromDB(fileSrcMd);
//        }catch (Exception e){
//            System.out.println("EMPException:" + e);
//        }
//     }



}
三、小结

这里还要对上面的file_src_md的字段做一下说明:因为老系统和前端静态资源交互方式用的是路径,而不是统一的fileId,所以去数据库中查资源的时候,只能拿路径去查。因为路径长度不一,而且查询效率不高,所以就设计了将路径的MD5放入数据库中,作为查询字段。

关注
打赏
1657848381
查看更多评论
立即登录/注册

微信扫码登录

0.0417s