要求数据库中断的情况下,部分功能能力放通:
实现思路:本想用csv文件存储临时数据,发现用数组拼装太麻烦,后直接采用对象序列化存储
采用读写所操作数据,在业务操作时,捕捉数据库中断异常,把对象写入缓存文件中,
数据库正常后,任意一个用户登陆,开辟一个线程进行读操作,写入数据库,然后删除缓存文件
过程中发现学序列化追加存储,无法正常读取,最后一个工具类是处理该问题的
/** * * 缓存文件读取 * <读取缓存文件,对缓存数据进行数据库持久化操作> * * @author xxx * @version [V01, 2011-9-6] * @see [相关类/方法] * @since [产品/模块版本] */ @Scope("prototype") @Component public class ReadTask extends Thread { private Log log = LogFactory.getLog(ReadTask.class); /** * 文件读写操作类 */ @Autowired private ReadWriteLockLogic readWriteLockOperator; @Autowired() private EventRepository eventRepository; /** * 执行读取任务 */ public synchronized void run() { if (this.readWriteLockOperator != null) { //1、读取文件拼装对象 List<EventBean> eventBeanList = null; try { eventBeanList = readWriteLockOperator.read(); } catch (Exception e) { log.error(e.getStackTrace()); } //4、删除文件 readWriteLockOperator.delete(); if (null == eventBeanList || eventBeanList.isEmpty()) { return; } //3、成功保存到数据库(如果出现异常,如果普通异常记录失败行数,如果是数据库中断,回滚) List<EventBean> faiList = eventRepository.insertEventLink(eventBeanList); if (null == faiList || faiList.isEmpty()) { return; } //5、对于数据库突然中断的数据,覆写回缓存文件 try { readWriteLockOperator.write(faiList, false); } catch (Exception e) { log.error(e.getStackTrace()); } } } }
/** * 文件读写操作类 * <针对文件的续写加入读写锁,避免冲突> * * @author xxx * @version [V1.0, 2011-9-6] * @see [相关类/方法] * @since [ECC/C02] */ @Component public class ReadWriteLockLogic { /** * 文件路径 */ private String path; /** * 初始化一个 ReadWriteLock */ private ReadWriteLock lock = new ReentrantReadWriteLock(); private Log log = LogFactory.getLog(ReadWriteLockLogic.class); /** * 读数据缓存文件 * * @return EventBean */ public List<EventBean> read() // throws Exception { // 得到 readLock 并锁定 Lock readLock = lock.readLock(); readLock.lock(); List<EventBean> eventBeanList = new ArrayList<EventBean>(); ObjectInputStream ois = null; FileInputStream fis = null; File file = new File(path); //赋予创建文件权限 // file.setWritable(true, false); if (!file.exists()) { return null; } try { fis = new FileInputStream(file); ois = new ObjectInputStream(fis); Object obj; while (fis.available() > 0) { obj = ois.readObject(); if (obj instanceof EventBean) { EventBean eventBean = (EventBean)obj; eventBeanList.add(eventBean); } } } catch (Exception e) { log.error(e.getStackTrace()); } finally { if (null != fis) { try { fis.close(); } catch (IOException e) { log.error(e.getStackTrace()); } } if (null != ois) { try { ois.close(); } catch (IOException e) { log.error(e.getStackTrace()); } } readLock.unlock();//一定要保证锁的释放 } return eventBeanList; } /** * 写文件 * * @param eventBeanList 事件对象 * @param isVerride 是否覆盖 * @return boolean 是否正确写入 */ public boolean write(List<EventBean> eventBeanList, boolean isVerride) // throws Exception { // 得到 writeLock 并锁定 Lock writeLock = lock.writeLock(); writeLock.lock(); //带有true参数的FileOutputStream EccObjectOutputStream outSteam = null; FileOutputStream fos = null; try { File file = new File(path); //赋予创建文件权限 // file.setWritable(true, false); if (!file.getParentFile().exists()) { try { if (!file.getParentFile().mkdirs()) { return false; } } catch (Exception e) { log.error(e.getStackTrace()); return false; } } if (!file.exists() && null != eventBeanList) { try { if (!file.createNewFile()) { return false; } } catch (Exception e) { log.error(e.getStackTrace()); return false; } } fos = new FileOutputStream(file, isVerride); outSteam = EccObjectOutputStream.newInstance(file, fos); if (null != eventBeanList) { for (EventBean eventBean : eventBeanList) { outSteam.writeObject(eventBean); } } outSteam.flush(); } catch (Exception e) { log.error(e.getStackTrace()); return false; } finally { if (null != fos) { try { fos.close(); } catch (IOException e) { log.error(e.getStackTrace()); } } if (null != outSteam) { try { outSteam.close(); } catch (IOException e) { log.error(e.getStackTrace()); } } writeLock.unlock();//一定要保证锁的释放 } return true; } /** * 删除文件 * 如果文件存在则删除文件 * * @return Boolean */ public Boolean delete() { File file = new File(path); if (file.exists()) { try { return file.delete(); } catch (Exception e) { log.error("delete dbcache file faild"); log.error(e.getStackTrace()); } } return false; } /** * 判断文件是否存在 * * @return Boolean */ public Boolean isExist() { File file = new File(path); return file.exists(); } public String getPath() { return path; } public void setPath(String path) { this.path = path; } }
/** * 缓存文件写入 * 事件bean加密转换为数组写入缓存文件中 * * @author xxx * @version [版本号, 2011-9-7] * @see [相关类/方法] * @since [产品/模块版本] */ @Component public class WriteTask { @Autowired private ReadWriteLockLogic readWriteLockOperator; /** * 缓存文件写方法 * * @param eventBeanList 事件对象集合 * @return RestResponse */ public RestResponse write(List<EventBean> eventBeanList) // throws Exception { RestResponse response = new RestResponse(); //同步读写锁数据按格式写入文件(加密) if (readWriteLockOperator.write(eventBeanList, true)) { response.setSuccess(true); response.setRetCode(ReturnCode.SUCCESS); } else { response.setRetCode(ReturnCode.FAILURE); response.setSuccess(false); } return response; } }
/** * * 针对输出流的封装类 * 解决序列化对象追加写入文件无法读取问题 * @author xxx * @version [版本号, 2011-9-9] * @see [相关类/方法] * @since [产品/模块版本] */ public class EccObjectOutputStream extends ObjectOutputStream { /** * 公共文件 */ private static File f; /** * 初始化静态文件对象,并返回类对象 * @param file 文件对象,用于初始化静态文件对象 * @param out 输出流 * @return MyObjectOutputStream * @throws IOException */ public static EccObjectOutputStream newInstance(File file, OutputStream out) throws IOException { f = file;//本方法最重要的地方:构建文件对象,是两个文件对象属于同一个 //return new EccObjectOutputStream(out, f); return new EccObjectOutputStream(out);//修改pmd问题 } /** * {@inheritDoc} */ @Override protected void writeStreamHeader() throws IOException { if (!f.exists() || (f.exists() && f.length() == 0)) { super.writeStreamHeader(); } else { super.reset(); } } /** * <默认构造函数> */ //public EccObjectOutputStream(OutputStream out, File f) //修改pmd问题 public EccObjectOutputStream(OutputStream out) throws IOException { super(out); } }