描述
在游戏服务器中,数据回写是指将内存中的数据回写更新到数据库(MongoDB),触发回写的情况通常有两种:
定时回写:每个一段时间将将数据刷新到数据库中
停服回写:在关闭游戏服务器时回写所有数据
设计方案
设计方案如下图,涉及到的接口和类概况:
delay():返回定时回写时间
run():执行定时回写操作
GameServer:游戏服务器
PlayerService:玩家数据业务
Player:玩家信息 Bean
IFlushTimer:定时回写接口,Bean 类需实现该接口的两个方法
DBFlushTimer:定时回写工具类,通过 ScheduledExecutorService 实现定时回写
数据回写
代码案例
定义 IFlushTimer 接口,继承自 Runnable
public interface IFlushTimer extends Runnable { int delay(); }
Bean 类实现 IFlushTimer 接口的 delay()、run() 方法
public class Player implements IFlushTimer { private int id; private String name; private ScheduledFuture<?> db_sf = null; public Player(int id, String name) { this.id = id; this.name = name; } @Override public int delay() { return 5; } @Override public void run() { this.flush(); } /** * 启动定时回写任务 */ public void startup() { db_sf = DBFlushTimer.add(this); } /** * 模拟数据库回写 */ private void flush() { System.out.println("id:" + this.id + "回写中..."); // 模拟回写操作延迟 try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } /** * 清除定时回写并回写数据 */ public void clear() { synchronized (db_sf) { db_sf.cancel(false); db_sf = null; } runClose(); } /** * 回写数据并执行其他操作 */ public void runClose() { this.flush(); } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
编写定时回写工具类 DBFlushTimer,需要注意的是这里使用的是 scheduleWithFixedDelay(...) 方法,ScheduledExecutorService 有两个方法:
scheduleAtFixedRate(...):固定每隔多少秒执行一次任务
scheduleWithFixedDelay(...):当前任务结束的时才开始结算间隔时间,如 0 秒开始执行第一次任务,任务耗时 5 秒,任务间隔时间 3 秒,那么第二次任务执行的时间是在第 8 秒开始
public class DBFlushTimer { private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); public static ScheduledFuture add(IFlushTimer timer){ ScheduledFuture scheduledFuture = scheduler.scheduleWithFixedDelay(timer,(long)timer.delay(),(long)timer.delay(),TimeUnit.SECONDS); return scheduledFuture; } }
编写业务类 PlayerService
public class PlayerService { public static final ConcurrentHashMap<Integer, Player> playerId2Player = new ConcurrentHashMap<Integer, Player>(); /** * 开服初始化,模拟从数据库加载玩家信息 */ public static void init() { Player p1 = new Player(1, "p1"); Player p2 = new Player(2, "p2"); PlayerService.playerId2Player.put(p1.getId(), p1); PlayerService.playerId2Player.put(p2.getId(), p2); // 启动定时回写 p1.startup(); p2.startup(); } /** * 停服回写所有数据 */ public static void flushToDB(){ System.out.println("flush player data to db ....."); for (Player player : playerId2Player.values()){ player.clear(); } System.out.println("flush tong data end ....."); } }
编写 GameServer
public class GameServer { public static void main(String[] args)throws Exception { init(); TimeUnit.SECONDS.sleep(12); stop(); } public static void init(){ System.out.println("init game server ....."); PlayerService.init(); } // 关服 public static void stop(){ System.out.println("stop game server ....."); PlayerService.flushToDB(); } }
作者:林塬
链接:https://www.jianshu.com/p/42e77dd614a9
共同學習,寫下你的評論
評論加載中...
作者其他優質文章