备份和恢复 HsqlDb 嵌入式文件(非数据库)

Posted

技术标签:

【中文标题】备份和恢复 HsqlDb 嵌入式文件(非数据库)【英文标题】:Backup and Restore HsqlDb Embeded File (NOT DATABASE) 【发布时间】:2016-12-22 21:20:21 【问题描述】:

每个人都在谈论备份Hsqldb,但我需要的是备份嵌入的文件......

我使用的是Spring JPA,应用程序一直在运行,所以文件在使用中,而且由于没有DBMS,我想知道是否有备份和恢复的方法? 如果有,请指导我...

否则,我想复制数据库文件,不知何故(不知道如何)将 spring JPA 置于离线模式,然后 ZIP 那些我在 java 中不知道的文件,然后让用户下载它,如果spring允许的话......不知何故(因为我使用独立的spring boot,它是一个文件,它不提供很多那些花哨的文件夹,我们可以将它们指向它们作为网站url......)

最终在任何情况下我都想将文件发送给客户端。

对不起,如果我对此一无所知,我来自 C#,5 年后,这是我第二次使用 Java,我从来没有成为它的专业人士。

更新

虽然我不确定我是否可以从正在运行的数据库制作一个 zip 文件,并将其存储在那个地方......我通过搜索编写了这段代码,我找到了几个返回当前目录的方法,但没有一个指向到我想要的目录...其中之一,在调试时它指向非常内部的位置,如 targer/class/x/y/z,在我将它打包到 jar 文件后,它可能会有所不同,另一个指向 C/ ..../temp, ...我需要写入我的数据库文件所在的位置,然后传递这些文件以制作 zip 文件功能,并告诉用户下载文件

@RestController
@RequestMapping(value = "/rest/database-manager")
public class DatabaseManager 

    private ServletContext servletContext;
    private final Environment env;

    @Autowired
    public DatabaseManager(Environment env, ServletContext servletContext) 
        this.env = env;
        this.servletContext = servletContext;
    

    @RequestMapping(value = "/get-backup", method=RequestMethod.GET)
    private FileSystemResource getBackup() throws IOException 
        //String directory = DemoApplication.class.getResource("").getPath();
        String outputLocation = servletContext.getRealPath("./");
        String dataBaseFilePath = servletContext.getRealPath(env.getProperty("application.database-file-location"));
        Calendar cal = new GregorianCalendar();
        String zipFile = outputLocation + "/backup-"
                + StrMgr.leftPad(String.valueOf(cal.get(Calendar.YEAR)), 4, "0")
                + StrMgr.leftPad(String.valueOf(cal.get(Calendar.MONTH)), 2, "0")
                + StrMgr.leftPad(String.valueOf(cal.get(Calendar.DAY_OF_MONTH)), 2, "0")
                + "-"
                + StrMgr.leftPad(String.valueOf(cal.get(Calendar.HOUR)), 2, "0")
                + StrMgr.leftPad(String.valueOf(cal.get(Calendar.MINUTE)), 2, "0")
                + StrMgr.leftPad(String.valueOf(cal.get(Calendar.SECOND)), 2, "0")
                + ".zip";
        ZipUtil.ToZip(new String[]"", zipFile);
        return new FileSystemResource(zipFile);
    

压缩功能:

public class ZipUtil 
    public static void ToZip(String inputFiles[], String outputFile) throws IOException 
        //create byte buffer
        byte[] buffer = new byte[1024];

                /*
                 * To create a zip file, use
                 *
                 * ZipOutputStream(OutputStream out)
                 * constructor of ZipOutputStream class.
                */

        //create object of FileOutputStream
        FileOutputStream fout = new FileOutputStream(outputFile);

        //create object of ZipOutputStream from FileOutputStream
        ZipOutputStream zout = new ZipOutputStream(fout);

        for (int i = 0; i < inputFiles.length; i++) 
            //create object of FileInputStream for source file
            FileInputStream fin = new FileInputStream(inputFiles[i]);

                        /*
                         * To begin writing ZipEntry in the zip file, use
                         *
                         * void putNextEntry(ZipEntry entry)
                         * method of ZipOutputStream class.
                         *
                         * This method begins writing a new Zip entry to
                         * the zip file and positions the stream to the start
                         * of the entry data.
                         */

            zout.putNextEntry(new ZipEntry(inputFiles[i]));

                        /*
                         * After creating entry in the zip file, actually
                         * write the file.
                         */
            int length;

            while ((length = fin.read(buffer)) > 0) 
                zout.write(buffer, 0, length);
            

                        /*
                         * After writing the file to ZipOutputStream, use
                         *
                         * void closeEntry() method of ZipOutputStream class to
                         * close the current entry and position the stream to
                         * write the next entry.
                         */

            zout.closeEntry();

            //close the InputStream
            fin.close();

        


        //close the ZipOutputStream
        zout.close();
    

完整答案:

我不确定生产是否有任何作用,因为我直接在里面写入响应,并返回void

我的回复方法:

    @RequestMapping(value = "/get-backup", method = RequestMethod.GET)
    private void getBackup(HttpServletResponse response) throws IOException 
        /*//String directory = DemoApplication.class.getResource("").getPath();
        String outputLocation = servletContext.getRealPath("./");
        String dataBaseFilePath = servletContext.getRealPath(env.getProperty("application.database-file-location"));
        Calendar cal = new GregorianCalendar();
        String zipFile = outputLocation + "/backup-"
                + StrMgr.leftPad(String.valueOf(cal.get(Calendar.YEAR)), 4, "0")
                + StrMgr.leftPad(String.valueOf(cal.get(Calendar.MONTH)), 2, "0")
                + StrMgr.leftPad(String.valueOf(cal.get(Calendar.DAY_OF_MONTH)), 2, "0")
                + "-"
                + StrMgr.leftPad(String.valueOf(cal.get(Calendar.HOUR)), 2, "0")
                + StrMgr.leftPad(String.valueOf(cal.get(Calendar.MINUTE)), 2, "0")
                + StrMgr.leftPad(String.valueOf(cal.get(Calendar.SECOND)), 2, "0")
                + ".zip";

        SQLQuery query = session.createSQLQuery("BACKUP DATABASE TO '/tmp/backup.tar.gz' BLOCKING");
        query.executeUpdate();*/

        File zipFile = null;

        Calendar cal = new GregorianCalendar();
        String prefix = "DBK-"
                + StrMgr.leftPad(String.valueOf(cal.get(Calendar.YEAR)), 4, "0")
                + StrMgr.leftPad(String.valueOf(cal.get(Calendar.MONTH)), 2, "0")
                + StrMgr.leftPad(String.valueOf(cal.get(Calendar.DAY_OF_MONTH)), 2, "0")
                + "-"
                + StrMgr.leftPad(String.valueOf(cal.get(Calendar.HOUR)), 2, "0")
                + StrMgr.leftPad(String.valueOf(cal.get(Calendar.MINUTE)), 2, "0")
                + StrMgr.leftPad(String.valueOf(cal.get(Calendar.SECOND)), 2, "0");
        String suffix = ".tar.gz";
        zipFile = File.createTempFile(prefix, suffix);

        zipFile.delete();

        databaseManagerRepository.Backup(zipFile.getAbsolutePath());

        response.setContentType("application/gzip");
        response.setHeader("Content-disposition", "attachment; filename=" + zipFile.getName());

//            OutputStream out = response.getOutputStream();
//            FileInputStream in = new FileInputStream(zipFile);
            /*
             * copy from in to out
             */
        OutputStream out = null;
        FileInputStream in = null;
        try 
            out = response.getOutputStream();
            in = new FileInputStream(zipFile);

            byte[] buffer = new byte[4096]; // To hold file contents
            int bytes_read; // How many bytes in buffer

            // Read a chunk of bytes into the buffer, then write them out,
            // looping until we reach the end of the file (when read() returns
            // -1). Note the combination of assignment and comparison in this
            // while loop. This is a common I/O programming idiom.
            while ((bytes_read = in.read(buffer)) != -1)
                // Read until EOF
                out.write(buffer, 0, bytes_read); // write
        
        catch (Exception ex)
            System.out.print(ex.getMessage());
        
        // Always close the streams, even if exceptions were thrown
        finally 
            if (in != null)
                try 
                    in.close();
                 catch (IOException e) 
                    ;
                
            if (out != null)
                try 
                    out.close();
                 catch (IOException e) 
                    ;
                
        

        zipFile.delete();
    

我的备份本机 SQL 操作执行器

@Repository
public class DatabaseManagerRepository 
    @PersistenceContext
    private EntityManager entityManager;

    /*The query force us to use transaction, and since the DB is online and we use spring, it also force us to use spring transaction*/
    @Transactional(rollbackFor = Exception.class)
    public void Backup(String outputDir) 
            //NOT BLOCKING -> For large database, backup is performed while the database perform other operations
            //AS FILES -> We only define directory not the file itself
            Query q = entityManager.createNativeQuery("BACKUP DATABASE TO '" + outputDir + "' BLOCKING"/*" AS FILES"*/);
            q.executeUpdate();
    

【问题讨论】:

【参考方案1】:

备份与 HSQLDB 服务器或嵌入式数据库相同。你执行 SQL 语句:

BACKUP DATABASE TO <directory name> BLOCKING AS FILES

目录名是存储备份文件的目标目录的路径。例如BACKUP DATABASE TO 'C://db_backups/' BLOCKING AS FILES

http://hsqldb.org/doc/2.0/guide/management-chapt.html#mtc_online_backup

AS FILES 备份数据库会创建一组可以压缩的文件。

【讨论】:

路径周围需要单引号字符。我正在更新我的答案。 这称为 MIME 类型。 “gz”扩展名通常是 setContentType("application/gzip")。注意 gzip 与 zip 不同。 在我提供的 URL 上阅读 HSQLDB 指南。 TransactionRequiredExcpetion 意味着您需要在执行之前启动事务。最后一条消息中的错误是因为您在 outputDir 周围使用双引号而不是单引号 按照我的建议写就行了。当你给它一个文件名时,你不使用 AS FILES。不使用文件名时,应提供空目录的路径,而不是 Temp 目录本身,也不要提供文件名。

以上是关于备份和恢复 HsqlDb 嵌入式文件(非数据库)的主要内容,如果未能解决你的问题,请参考以下文章

本地操作系统备份还原介绍

如何备和恢复Ubuntu系统

本地备异地保存份

本地备异地保存份

使用UCACHE灾备云帮操作系统实现增量备份

从 HSQLDB LOBS 文件增长中恢复的最佳方法