• JRT实现缓存协议


    上一篇介绍的借助ORM的增、删、改和DolerGet方法,ORM可以很精准的知道热点数据做内存缓存。那么就有一个问题存在,即部署了多个站点时候,如果用户在一个Web里修改数据了,那么其他Web的ORM是不知道这个变化的,其他Web还是缓存的老数据的话就会造成其他Web命中的缓存数据是老的,造成不可靠问题。

    那么就需要一种机制来解决多Web缓存不一致问题,参照ECP实现,把Web分为主服务器和从服务器。主服务器启动TCP服务端,从服务器启动TCP客户端连接主服务器,从服务器和主服务器之间一直保留TCP长连接用来通知缓存变化数据。这样在一个服务器增、删、改数据后就能及时通知其他服务器更新缓存,这样所有服务器的缓存数据都是可信赖的。

    首先提取发送数据的对象类型
    在这里插入图片描述

    然后实现ECP管理类ECPManager来管理启动服务端和客户端

    package JRT.DAL.ORM.Global;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStreamWriter;
    import java.io.PrintWriter;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.util.ArrayList;
    import java.util.Hashtable;
    import java.util.List;
    import java.util.concurrent.ConcurrentHashMap;
    import java.util.concurrent.ConcurrentLinkedDeque;
    
    import JRT.Core.Util.LogUtils;
    import JRT.DAL.ORM.Global.ECPDto;
    
    /**
     * 企业缓存协议,基于TCP在多台服务器直接共享缓存的更新,从而确保每个Web下的缓存数据的可靠性,这里实现TCP服务端当做小机,其他服务当做客户端和小机连接。
     * 小机会分发增加数据(增加数据分发与否倒是不影响缓存可靠性,主要是修改和删除)、修改数据、删除数据的执行记录给每个客户端,客户端按收到的记录把数据推入缓存
     */
    public class ECPManager {
        /**
         * 要推入TCP的缓存队列
         */
        public static ConcurrentLinkedDeque ECPQuen = new ConcurrentLinkedDeque();
    
        /**
         * 主处理进程
         */
        private static Thread MainThread = null;
    
        /**
         * 发送数据的操作对象
         */
        public static Socket Sender = null;
    
        /**
         * 写操作对象
         */
        public static PrintWriter Writer = null;
    
        /**
         * 数据编码
         */
        private static String Encode="GBK";
    
        /**
         * 缓存所有客户端
         */
        private static ConcurrentHashMap<String,Socket> AllClient= new ConcurrentHashMap<>();
    
        /**
         * IP地址
         */
        private static String IP="";
    
        /**
         * 端口
         */
        private static  int Port=1991;
    
        /**
         * 是否启用了ECP
         */
        private static boolean UseEcp=false;
    
        /**
         * 加入缓存,直接缓存,具体的后续有缓存管理器线程维护缓存,这里只管加入队列即可
         *
         * @param obj
         * @throws Exception
         */
        public static void InECPToQuen(ECPDto obj) throws Exception{
            ECPQuen.add(obj);
        }
    
        /**
         * push目前的ECP缓存数据到远程服务器,供GlobalManager定时器定时推送
         */
        public static void TryPushEcp() throws Exception
        {
            try {
                //如果是客户端,先检查连接
                if (!IP.isEmpty()) {
                    //重连
                    if (Sender == null || Sender.isClosed()) {
                        LogUtils.WriteSecurityLog("ECP尝试重连:" + IP + ":" + Port);
                        StartEcpManager(IP, Port);
                        Thread.sleep(1000);
                    }
                    if (Sender == null || Sender.isClosed()) {
                        return;
                    } else {
                        LogUtils.WriteSecurityLog("ECP尝试重连成功:" + IP + ":" + Port);
                    }
                }
                List<ECPDto> pushList=null;
                //从缓存队列里面弹出数据push
                while (ECPQuen.size() > 0) {
                    ECPDto obj = (ECPDto)ECPQuen.pop();
                    if (obj != null) {
                        //启用了ECP就push到服务端,否则就只更新自己缓存
                        if(UseEcp==true)
                        {
                            //初始化push列表
                            if(pushList==null)
                            {
                                pushList=new ArrayList<>();
                            }
                            pushList.add(obj);
                        }
                        else
                        {
                            //转换成数据实体推入缓存
                            JRT.DAL.ORM.Global.GlobalManager.InCache(obj);
                        }
                    }
                }
                //直接列表一次推送,没有启用ECP的话这个列表一直是空
                if(pushList!=null)
                {
                    //客户端推送
                    if (!IP.isEmpty()) {
                        Writer.print(JRT.Core.Util.JsonUtil.Object2Json(pushList));
                        Writer.flush();
                    }
                    //服务端推送
                    else {
                        //给每个连接的客户端推送信息
                        for (String ip : AllClient.keySet()) {
                            Socket oneClient = AllClient.get(ip);
                            //移除关闭的客户端
                            if (oneClient.isClosed()) {
                                AllClient.remove(ip);
                            }
                            PrintWriter oneWriter = new PrintWriter(new OutputStreamWriter(oneClient.getOutputStream(), Encode), false);
                            oneWriter.print(JRT.Core.Util.JsonUtil.Object2Json(pushList));
                            oneWriter.flush();
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                LogUtils.WriteExceptionLog("推送数据到ECP异常", ex);
            }
        }
    
        /**
         * 启动ECP管理
         * @param ip
         * @param port
         */
        public static void StartEcpManager(String ip, int port)
        {
            IP=ip;
            Port=port;
            //当客户端
            if (!ip.isEmpty()) {
                MainThread = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        //得到输入流
                        InputStream inputStream = null;
                        //创建Socket对象并连接到服务端
                        Socket socket = null;
                        try {
                            //创建Socket对象并连接到服务端
                            socket = new Socket(ip, port);
                            Sender = socket;
                            Writer = new PrintWriter(new OutputStreamWriter(Sender.getOutputStream(), Encode), false);
                            //得到输入流
                            inputStream = socket.getInputStream();
                            //IO读取
                            byte[] buf = new byte[10240];
                            int readlen = 0;
                            //阻塞读取数据
                            while ((readlen = inputStream.read(buf)) != -1) {
                                try {
                                    String ecpJson = new String(buf, 0, readlen, Encode);
                                    //得到ECP实体
                                    List<ECPDto> dtoList = (List<ECPDto>)JRT.Core.Util.JsonUtil.Json2Object(ecpJson, ECPDto.class);
                                    if(dtoList!=null&&dtoList.size()>0)
                                    {
                                        for(ECPDto dto:dtoList) {
                                            //转换成数据实体推入缓存
                                            JRT.DAL.ORM.Global.GlobalManager.InCache(dto);
                                        }
                                    }
                                }
                                catch (Exception ee)
                                {
                                    LogUtils.WriteExceptionLog("ECP处理主服务器数据异常", ee);
                                }
                            }
                        }
                        catch (IOException ex) {
                            LogUtils.WriteExceptionLog("ECP侦听TCP服务异常", ex);
                        }
                        finally {
                            Sender=null;
                            try {
                                if (inputStream != null) {
                                    //关闭输入
                                    inputStream.close();
                                }
                                if (Writer != null) {
                                    Writer.flush();
                                    //关闭输出
                                    Writer.close();
                                    Writer=null;
                                }
                                if (socket != null) {
                                    // 关闭连接
                                    socket.close();
                                }
                            }
                            catch (Exception ex) {
                                LogUtils.WriteExceptionLog("释放TCP资源异常", ex);
                            }
    
                        }
                    }
                });
    
            }
            //当服务端
            else {
                MainThread = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        //得到输入流
                        InputStream inputStream = null;
                        //创建Socket对象并连接到服务端
                        Socket socket = null;
                        try {
                            ServerSocket serverSocket = new ServerSocket(port);
                            //增加一个无限循环
                            while (true) {
                                //等待客户端连接,阻塞
                                Socket clientSocket = serverSocket.accept();
                                //按IP存客户端连接
                                String clientIP=clientSocket.getInetAddress().getHostAddress();
                                AllClient.put(clientIP,clientSocket);
                                //接收客户端消息
                                Thread ClientThread = new Thread(new Runnable() {
                                    @Override
                                    public void run() {
                                        try {
                                            //得到输出流
                                            Writer = new PrintWriter(new OutputStreamWriter(clientSocket.getOutputStream(), Encode), false);
                                            //得到输入流
                                            InputStream inputStream = clientSocket.getInputStream();
                                            //IO读取
                                            byte[] buf = new byte[10240];
                                            int readlen = 0;
                                            //阻塞读取数据
                                            while ((readlen = inputStream.read(buf)) != -1) {
                                                String ecpJson = new String(buf, 0, readlen, Encode);
                                                //得到ECP实体
                                                List<ECPDto> dtoList = (List<ECPDto>)JRT.Core.Util.JsonUtil.Json2Object(ecpJson, ECPDto.class);
                                                if(dtoList!=null&&dtoList.size()>0)
                                                {
                                                    for(ECPDto dto:dtoList) {
                                                        //转换成数据实体推入缓存
                                                        JRT.DAL.ORM.Global.GlobalManager.InCache(dto);
                                                    }
                                                    //给每个连接的客户端推送信息
                                                    for (String ip : AllClient.keySet()) {
                                                        Socket oneClient = AllClient.get(ip);
                                                        //移除关闭的客户端
                                                        if (oneClient.isClosed()) {
                                                            AllClient.remove(ip);
                                                        }
                                                        PrintWriter oneWriter = new PrintWriter(new OutputStreamWriter(oneClient.getOutputStream(), Encode), false);
                                                        oneWriter.print(ecpJson);
                                                        oneWriter.flush();
                                                    }
                                                }
                                            }
                                        }
                                        catch (Exception ee)
                                        {
                                            LogUtils.WriteExceptionLog("ECP处理客户端数据异常", ee);
                                        }
                                    }
                                });
                                ClientThread.start();
                            }
                        }
                        catch (IOException ex) {
                            LogUtils.WriteExceptionLog("侦听仪器TCP异常", ex);
                        }
                        finally {
                            try {
                                if (inputStream != null) {
                                    //关闭输入
                                    inputStream.close();
                                }
                                if (Writer != null) {
                                    Writer.flush();
                                    //关闭输出
                                    Writer.close();
                                }
                                if (socket != null) {
                                    // 关闭连接
                                    socket.close();
                                }
                            } catch (Exception ex) {
                                LogUtils.WriteExceptionLog("释放TCP资源异常", ex);
                            }
    
                        }
                    }
                });
            }
            //启动主进程
            MainThread.start();
            UseEcp=true;
        }
    
        /**
         * 返回ECP待处理队列的json数据供调试看是否符合预期
         * @return
         */
        public static String ViewECPQuenDate() throws Exception
        {
            return JRT.Core.Util.JsonUtil.Object2Json(ECPQuen);
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333

    ECP管理类再对接上GlobalManager

    package JRT.DAL.ORM.Global;
    
    import java.io.OutputStreamWriter;
    import java.io.PrintWriter;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Timer;
    import java.util.TimerTask;
    import java.util.concurrent.ConcurrentHashMap;
    import java.util.concurrent.ConcurrentLinkedDeque;
    import java.util.concurrent.atomic.AtomicInteger;
    
    import JRT.Core.MultiPlatform.JRTConfigurtaion;
    import JRT.Core.Util.LogUtils;
    import JRT.DAL.ORM.Global.OneGlobalNode;
    import JRT.DAL.ORM.Global.ECPDto;
    
    /**
     * 实现内存模拟global的效果
     */
    public class GlobalManager {
        /**
         * 在内存里缓存热点数据
         */
        private static ConcurrentHashMap<String, ConcurrentHashMap<String, OneGlobalNode>> AllHotData = new ConcurrentHashMap<>();
    
        /**
         * 要缓存数据的队列
         */
        private static ConcurrentLinkedDeque TaskQuen = new ConcurrentLinkedDeque();
    
        /**
         * 管理缓存的定时器
         */
        private static Timer ManageTimer = new Timer();
    
        /**
         * 缓存的最大对象数量
         */
        public static Integer GlobalCacheNum = 100000;
    
        /**
         * 当前的缓存数量
         */
        private static AtomicInteger CurCacheNum=new AtomicInteger(0);
    
        /**
         * 最后删除数据的时间
         */
        private static Long LastDeleteTime=null;
    
        /**
         * 加入缓存,直接缓存,具体的后续有缓存管理器线程维护缓存,这里只管加入队列即可
         *
         * @param obj
         * @throws Exception
         */
        public static void InCache(ECPDto obj) throws Exception{
            TaskQuen.add(obj);
        }
    
        /**
         * 通过主键查询数据
         * @param model
         * @param id
         * @param 
         * @return
         * @throws Exception
         */
        public static <T> T DolerGet(T model,Object id) throws Exception
        {
            //实体的名称
            String modelName = model.getClass().getName();
            if(AllHotData.containsKey(modelName))
            {
                //命中数据,克隆返回
                if(AllHotData.get(modelName).containsKey(id))
                {
                    OneGlobalNode node=AllHotData.get(modelName).get(id);
                    //更新时间
                    node.Time=JRT.Core.Util.TimeParser.GetTimeInMillis();
                    Object retObj=JRT.Core.Util.JsonUtil.CloneObject(node.Data);
                    return (T)retObj;
                }
            }
            return null;
        }
    
        /**
         * 启动缓存数据管理的线程
         */
        public static void StartGlobalManagerTask() throws Exception{
            //最大缓存数量
            String GlobalCacheNumConf = JRTConfigurtaion.Configuration("GlobalCacheNum");
            if (GlobalCacheNumConf != null && !GlobalCacheNumConf.isEmpty()) {
                GlobalCacheNum = JRT.Core.Util.Convert.ToInt32(GlobalCacheNumConf);
            }
            //定时任务
            TimerTask timerTask = new TimerTask() {
                @Override
                public void run() {
                    try {
                        //缓存队列的数据并入缓存
                        while (TaskQuen.size() > 0) {
                            //处理要加入缓存的队列
                            DealOneDataQuen();
                        }
                        //尝试推送ECP数据到主服务
                        JRT.DAL.ORM.Global.ECPManager.TryPushEcp();
                        //清理多余的缓存数据,这里需要讲究算法,要求在上百万的缓存数据里快速找到时间最久远的数据
                        if(CurCacheNum.get()>GlobalCacheNum)
                        {
                            //每轮清理时间处于上次清理时间和当前时间前百分之5的老数据
                            long Diff=(JRT.Core.Util.TimeParser.GetTimeInMillis()-LastDeleteTime)/20;
                            //留下数据的最大时间
                            long LeftMaxTime=LastDeleteTime+Diff;
                            //遍历所有的热点数据
                            for (String model : AllHotData.keySet()) {
                                ConcurrentHashMap<String, OneGlobalNode> oneTableHot=AllHotData.get(model);
                                //记录要删除的数据
                                List<String> delList=new ArrayList<>();
                                for (String key : oneTableHot.keySet()) {
                                    OneGlobalNode one=oneTableHot.get(key);
                                    //需要删除的数据
                                    if(one.Time<LeftMaxTime)
                                    {
                                        delList.add(key);
                                    }
                                }
                                //移除时间久的数据
                                for(String del:delList)
                                {
                                    oneTableHot.remove(del);
                                }
                            }
                        }
                        //清理时间久远的缓存数据
                    } catch (Exception ex) {
                        LogUtils.WriteExceptionLog("处理Global缓存异常", ex);
                    }
                }
            };
            //尝试启动ECP管理器
            String IP = JRTConfigurtaion.Configuration("ECPIP");
            String Port = JRTConfigurtaion.Configuration("ECPPort");
            if(Port!=null&&!Port.isEmpty())
            {
                if(IP==null)
                {
                    IP="";
                }
                //启动ECP管理器
                JRT.DAL.ORM.Global.ECPManager.StartEcpManager(IP,JRT.Core.Util.Convert.ToInt32(Port));
            }
            //启动缓存管理定时器
            ManageTimer.schedule(timerTask, 0, 500);
    
        }
    
        /**
         * 通过实体名称获得实体类型信息
         *
         * @param modelName 实体名称
         * @return
         */
        private static Class GetTypeByName(String modelName) throws Exception {
            return JRT.Core.Util.ReflectUtil.GetType(JRT.Core.MultiPlatform.JRTConfigurtaion.Configuration("ModelName") + ".Entity." + modelName, JRT.Core.MultiPlatform.JRTConfigurtaion.Configuration("ModelName"));
        }
    
    
        /**
         * 处理队列里的一条数据并入缓存
         */
        private static void DealOneDataQuen() {
            try {
                Object obj = TaskQuen.pop();
                if (obj != null) {
                    ECPDto dto=(ECPDto)obj;
                    //添加或者更新缓存
                    if(dto.Cmd.equals("A")||dto.Cmd.equals("U")) {
                        Class type = GetTypeByName(dto.Model);
                        Object entity = JRT.Core.Util.JsonUtil.Json2Object(dto.Data, type);
                        JRT.DAL.ORM.Common.TableInfo tableInfo = JRT.DAL.ORM.Common.ModelToSqlUtil.GetTypeInfo(entity);
                        //实体的名称
                        String modelName = dto.Model;
                        //得到数据的主键
                        String id = tableInfo.ID.Value.toString();
                        if (!AllHotData.containsKey(modelName)) {
                            ConcurrentHashMap<String, OneGlobalNode> map = new ConcurrentHashMap<>();
                            AllHotData.put(modelName, map);
                        }
                        //更新数据
                        if (AllHotData.get(modelName).containsKey(id)) {
                            AllHotData.get(modelName).get(id).Data = entity;
                            AllHotData.get(modelName).get(id).Time = JRT.Core.Util.TimeParser.GetTimeInMillis();
                        }
                        //加入到缓存
                        else {
                            OneGlobalNode node = new OneGlobalNode();
                            node.Data = entity;
                            node.Time = JRT.Core.Util.TimeParser.GetTimeInMillis();
                            AllHotData.get(modelName).put(id, node);
                            //缓存数量加1
                            CurCacheNum.addAndGet(1);
                            //记录时间
                            if (LastDeleteTime == null) {
                                LastDeleteTime = JRT.Core.Util.TimeParser.GetTimeInMillis();
                            }
                        }
                    }
                    //删除缓存
                    else if(dto.Cmd.equals("D"))
                    {
                        Class type = GetTypeByName(dto.Model);
                        Object entity = JRT.Core.Util.JsonUtil.Json2Object(dto.Data, type);
                        JRT.DAL.ORM.Common.TableInfo tableInfo = JRT.DAL.ORM.Common.ModelToSqlUtil.GetTypeInfo(entity);
                        //实体的名称
                        String modelName = dto.Model;
                        //得到数据的主键
                        String id = tableInfo.ID.Value.toString();
                        if (AllHotData.containsKey(modelName)&&AllHotData.get(modelName).containsKey(id)) {
                            AllHotData.get(modelName).remove(id);
                        }
                    }
                    //清空表缓存
                    else if(dto.Cmd.equals("CLEAR"))
                    {
                        //实体的名称
                        String modelName = dto.Model;
                        if (AllHotData.containsKey(modelName)) {
                            AllHotData.get(modelName).clear();
                        }
                    }
                }
            }
            catch (Exception ex) {
                LogUtils.WriteExceptionLog("处理Global缓存添加异常", ex);
            }
        }
    
        /**
         * 返回Global的json数据供调试看是否符合预期
         * @return
         */
        public static String ViewGlobalJson() throws Exception
        {
            return JRT.Core.Util.JsonUtil.Object2Json(AllHotData);
        }
    
        /**
         * 返回Global待处理队列的json数据供调试看是否符合预期
         * @return
         */
        public static String ViewGlobalTaskQuenDate() throws Exception
        {
            return JRT.Core.Util.JsonUtil.Object2Json(TaskQuen);
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260

    增删改和DolerGet调整

    /**
         * 保存对象,不抛异常,执行信息通过参数输出
         *
         * @param entity   实体对象
         * @param outParam 输出执行成功或失败信息,执行成功时输出执行记录主键
         * @param       实体类型约束
         * @return影响行数
         */
        @Override
        public <T> int Save(T entity, OutValue outValue, OutParam outParam) throws Exception {
            int row = 0;
            PreparedStatement stmt = null;
            boolean innerT = false;     //标识是否内部开启事务
            String sql = "";
            try {
                //根据实体对象获取表信息
                JRT.DAL.ORM.Common.TableInfo tableInfo = JRT.DAL.ORM.Common.ModelToSqlUtil.GetTypeInfo(entity);
                HashParam hash = new HashParam();
                //获取插入SQL语句
                sql = JRT.DAL.ORM.Common.ModelToSqlUtil.GetInsertSqlByTableInfo(Manager().GetIDbFactory(factoryName), tableInfo, hash, false);
                //写SQL日志
                JRT.Core.Util.LogUtils.WriteSqlLog("执行插入SQL:" + sql + ";SQL参数:" + JRT.Core.Util.JsonUtil.Object2Json(hash.GetParam()));
                //获取ID列
                String idKey = tableInfo.ID.Key;
                //声明式SQL,并设置参数
                if (!idKey.isEmpty()) {
                    stmt = Manager().Connection().prepareStatement(sql, new String[]{idKey});
                } else {
                    stmt = Manager().Connection().prepareStatement(sql);
                }
                String paraSql = DBParaUtil.SetDBPara(stmt, hash.GetParam());
                row = stmt.executeUpdate();
                ResultSet rowID = stmt.getGeneratedKeys();
                JRT.Core.Util.LogUtils.WriteSqlLog("参数:" + paraSql);
                //保存成功返回记录主键,返回影响记录数 1
                if (row == 1) {
                    if (rowID.next() && (!idKey.isEmpty())) {
                        outValue.Value = rowID.getInt(idKey);
                        //设置RowID到实体
                        JRT.Core.Util.ReflectUtil.SetObjValue(entity, tableInfo.ID.Key, rowID.getInt(idKey));
                        //尝试把数据推入缓存队列
                        Manager().TryPushToCache(entity, "A");
                    }
                } else {
                    outParam.Code = OutStatus.ERROR;
                    outParam.Message = "保存数据失败,执行保存返回:" + row;
                }
                return row;
            } catch (Exception ex) {
                outParam.Code = OutStatus.ERROR;
                //操作异常,判断如果开启事务,则回滚事务
                if (Manager().Hastransaction) {
                    if (!Manager().RollTransaction()) {
                        outParam.Message = "保存数据失败!" + ex.getCause().getMessage() + ";回滚事务失败。";
                    }
                }
                outParam.Message = "保存数据失败!" + ex.getCause().getMessage() + "执行SQL:" + sql;
            }
            //操作结束释放资源
            finally {
                if (stmt != null) {
                    stmt.close();
                }
                //如果上层调用未开启事务,则调用结束释放数据库连接
                if (!Manager().Hastransaction) {
                    Manager().Close();
                }
            }
            return row;
        }
    
    
    /**
         * 更新实体对象
         *
         * @param entity        实体对象
         * @param param         更新条件,有条件就按条件更新,没有条件就按主键更新
         * @param outParam      输出执行成功或失败的信息
         * @param updateColName 更新属性名集合,无属性则更新实体的所有属性
         * @param joiner        连接符,为空或不给则按则按且连接,给的话长度应该比参数长度少1,如: and
         * @param operators     操作符,为空或不给的话各条件按等来比较,给的话长度应该跟参数长度一样,如: !=
         * @param            类型限定符
         * @return 影响行数
         */
        @Override
        public <T> int Update(T entity, HashParam param, OutParam outParam, List<String> updateColName, List<String> joiner, List<String> operators) throws Exception {
            PreparedStatement stmt = null;
            if (outParam == null) outParam = new OutParam();
            int row = 0;
            boolean innerT = false;     //标识是否内部开启事务
            try {
                //根据实体获取表信息
                JRT.DAL.ORM.Common.TableInfo tableInfo = JRT.DAL.ORM.Common.ModelToSqlUtil.GetTypeInfo(entity);
                HashParam hash = new HashParam();
                //获取更新的SQL语句
                String sql = JRT.DAL.ORM.Common.ModelToSqlUtil.GetUpdateSqlByTableInfo(Manager().GetIDbFactory(factoryName), tableInfo, param, updateColName, joiner, operators, hash);
                //写SQL日志
                JRT.Core.Util.LogUtils.WriteSqlLog("执行更新SQL:" + sql);
                //声明式SQL,并且设置参数
                stmt = Manager().Connection().prepareStatement(sql);
                String paraSql = DBParaUtil.SetDBPara(stmt, hash.GetParam());
                row = stmt.executeUpdate();
                JRT.Core.Util.LogUtils.WriteSqlLog("参数:" + paraSql);
                if (row == 1) {
                    //尝试把数据推入缓存队列
                    Manager().TryPushToCache(entity, "U");
                }
                outParam.Code = OutStatus.SUCCESS;
                outParam.Message = "更新数据成功。";
                return row;
            } catch (Exception ex) {
                //操作异常,判断如果开启了事务,就回滚事务
                outParam.Code = OutStatus.ERROR;
                if (Manager().Hastransaction) {
                    if (!Manager().RollTransaction()) {
                        outParam.Message = "更新数据失败!" + ex.getCause().getMessage() + ";回滚事务失败。";
                    }
                }
                outParam.Message = "更新数据失败!" + ex.getCause().getMessage();
            }
            //操作结束释放资源
            finally {
                if (stmt != null) {
                    stmt.close();
                }
                //如果上层调用未开启事务,则调用结束释放数据库连接
                if (!Manager().Hastransaction) {
                    Manager().Close();
                }
            }
            return row;
        }
    
    
    /**
         * 根据条件删除记录
         *
         * @param entity    实体对象
         * @param param     删除条件,有条件按条件删除,没有条件按主键删除
         * @param outParam  输出执行成功或失败的信息
         * @param joiner    多条件逻辑连接符,为空或不给则按则按且连接,给的话长度应该比参数长度少1,如: and
         * @param operators 操作符,为空或不给的话各条件按等来比较,给的话长度应该跟参数长度一样,如: !=
         * @param        类型限定符
         * @return 影响行数
         */
        @Override
        public <T> int Remove(T entity, HashParam param, OutParam outParam, List<String> joiner, List<String> operators) throws Exception {
            PreparedStatement stmt = null;
            if (outParam == null) outParam = new OutParam();
            int row = 0;
            try {
                //根据实体对象获取表信息
                JRT.DAL.ORM.Common.TableInfo tableInfo = JRT.DAL.ORM.Common.ModelToSqlUtil.GetTypeInfo(entity);
                HashParam hash = new HashParam();
                //获取删除SQL语句
                String sql = JRT.DAL.ORM.Common.ModelToSqlUtil.GetDeleteSqlByTableInfo(Manager().GetIDbFactory(factoryName), tableInfo, param, joiner, operators, hash);
                //写SQL日志
                JRT.Core.Util.LogUtils.WriteSqlLog("执行删除SQL:" + sql);
                //声明式SQL,并设置参数
                stmt = Manager().Connection().prepareStatement(sql);
                String paraSql = DBParaUtil.SetDBPara(stmt, hash.GetParam());
                row = stmt.executeUpdate();
                if (row == 1) {
                    //尝试把数据推入缓存队列
                    Manager().TryPushToCache(entity, "D");
                }
                JRT.Core.Util.LogUtils.WriteSqlLog("参数:" + paraSql);
                outParam.Code = OutStatus.SUCCESS;
                outParam.Message = "删除数据成功。";
                return row;
            } catch (Exception ex) {
                //操作异常,判断如果开启了事务,就回滚事务
                outParam.Code = OutStatus.ERROR;
                if (Manager().Hastransaction) {
                    if (!Manager().RollTransaction()) {
                        outParam.Message = "更新数据失败!" + ex.getCause().getMessage() + ";回滚事务失败。";
                    }
                }
                outParam.Message = "更新数据失败!" + ex.getCause().getMessage();
            }
            //操作结束释放资源
            finally {
                if (stmt != null) {
                    stmt.close();
                }
                //如果上层调用未开启事务,则调用结束释放数据库连接
                if (!Manager().Hastransaction) {
                    Manager().Close();
                }
            }
            return row;
        }
    
    /**
         * 通过主键查询数据,带缓存的查询,用来解决关系库的复杂关系数据获取,顶替Cache的$g
         *
         * @param model 实体
         * @param id    主键
         * @param 
         * @return
         * @throws Exception
         */
        public <T> T DolerGet(T model, Object id) throws Exception {
            T ret = GlobalManager.DolerGet(model, id);
            //命中缓存直接返回
            if (ret != null) {
                return ret;
            }
            else {
                //调用数据库查询
                ret = GetById(model, id);
                //找到数据,推入缓存
                if(ret!=null) {
                    ECPDto dto = new ECPDto();
                    dto.Cmd = "A";
                    dto.Model = ret.getClass().getSimpleName();
                    dto.Data = JRT.Core.Util.JsonUtil.Object2Json(ret);
                    //通知存入缓存
                    GlobalManager.InCache(dto);
                }
            }
            return ret;
        }
    
    /**
         * 通过主键查询数据,主业务数据没找到会按历史切割数量找历史表
         *
         * @param model
         * @param id
         * @param 
         * @return
         * @throws Exception
         */
        public <T> T GetById(T model, Object id) throws Exception {
            JRT.DAL.ORM.Common.TableInfo tableInfo = JRT.DAL.ORM.Common.ModelToSqlUtil.GetTypeInfo(model);
            List<ParamDto> param = new ArrayList<>();
            ParamDto p = new ParamDto();
            p.Key = tableInfo.ID.Key;
            p.Value = id;
            param.add(p);
            //创建实体集合
            List<T> lstObj = FindAll(model, param, "", -1, -1, "", null, null);
            //结果为空,返回一个新建的对象
            if (lstObj.size() == 0) {
                //从历史表取数据
                String HisTableName = tableInfo.TableInfo.HisTableName();
                if (!HisTableName.isEmpty()) {
                    int cutNum=0;
                    //指定了切割列按切割列切割
                    if(!tableInfo.TableInfo.CutHisColName().isEmpty())
                    {
                        cutNum=JRT.Core.Util.Convert.ToInt32(JRT.Core.Util.ReflectUtil.GetObjValue(model,tableInfo.TableInfo.CutHisColName()).toString());
                    }
                    else
                    {
                        cutNum=JRT.Core.Util.Convert.ToInt32(tableInfo.ID.Value.toString());
                    }
                    //除以历史页大小算到数据该放入哪个历史表
                    int hisNum = cutNum/HistoryPage;
                    //分割所有历史实体
                    String[] HisTableNameArr = HisTableName.split("^");
                    //存放页小于所有历史表数据就做移动
                    if (hisNum < HisTableNameArr.length) {
                        String HisModelName = HisTableNameArr[hisNum];
                        //得到历史表的实体
                        Class cHis = GetTypeByName(HisModelName);
                        //克隆得到历史表的对象
                        Object hisData = JRT.Core.Util.JsonUtil.CloneObject(model, cHis);
                        //创建实体集合
                        List<T> lstHisObj = DolerFindAll(0,hisData, param, "", -1, -1, "", null, null);
                        //结果为空,返回一个新建的对象
                        if (lstHisObj.size() > 0) {
                            return lstHisObj.get(0);
                        }
                    }
                }
                return null;
            }
            //否则返回第一个实体
            else {
                return lstObj.get(0);
            }
        }
    
        /**
         * 把数据安装维护的历史表大小移入历史表
         *
         * @param model 实体数据
         * @param    泛型
         * @return 是否成功
         * @throws Exception
         */
        public <T> boolean MoveToHistory(T model) throws Exception {
            JRT.DAL.ORM.Common.TableInfo tableInfo = JRT.DAL.ORM.Common.ModelToSqlUtil.GetTypeInfo(model);
            String HisTableName = tableInfo.TableInfo.HisTableName();
            if (!HisTableName.isEmpty()) {
                //分割所有历史实体
                String[] HisTableNameArr = HisTableName.split("^");
                int cutNum=0;
                //指定了切割列按切割列切割
                if(!tableInfo.TableInfo.CutHisColName().isEmpty())
                {
                    cutNum=JRT.Core.Util.Convert.ToInt32(JRT.Core.Util.ReflectUtil.GetObjValue(model,tableInfo.TableInfo.CutHisColName()).toString());
                }
                else
                {
                    cutNum=JRT.Core.Util.Convert.ToInt32(tableInfo.ID.Value.toString());
                }
                //除以历史页大小算到数据该放入哪个历史表
                int hisNum = cutNum/HistoryPage;
                //存放页小于所有历史表数据就做移动
                if (hisNum < HisTableNameArr.length) {
                    String HisModelName = HisTableNameArr[hisNum];
                    //得到历史表的实体
                    Class cHis = GetTypeByName(HisModelName);
                    //克隆得到历史表的对象
                    Object newData = JRT.Core.Util.JsonUtil.CloneObject(model, cHis);
                    OutParam out = new OutParam();
                    //保存历史数据
                    int saveRet = Save(newData, out);
                    if (saveRet == 1) {
                        saveRet = Remove(model, out);
                    }
                    if (saveRet == 1) {
                        return true;
                    }
                }
            }
            return false;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330

    连接管理类调整,根据是否带事务在操作执行成功后把数据推入ECP队列供Global管理器往主服务推送分发

    package JRT.DAL.ORM.DBUtility;
    
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.SQLException;
    import java.sql.Savepoint;
    import java.util.ArrayList;
    import java.util.LinkedList;
    import java.util.List;
    import java.util.concurrent.ConcurrentHashMap;
    
    import JRT.DAL.ORM.DBUtility.C3P0Util;
    import com.mchange.v2.c3p0.ComboPooledDataSource;
    import JRT.DAL.ORM.DBUtility.IDbFactory;
    import JRT.DAL.ORM.Global.ECPDto;
    
    /**
     * 连接和事务管理
     */
    public class DBManager {
        /**
         * 驱动名称
         */
        private String factoryName="";
    
        /**
         * 当前对象的驱动
         */
        private IDbFactory factory=null;
    
    
        /**
         * 存数据库连接对象
         */
        private Connection connection=null;
    
        /**
         * 要转入缓存的临时数据
         */
        private List<ECPDto> ToEcpTmp=null;
    
        /**
         * 尝试把数据推入缓存队列
         * @param obj 对象
         * @param Oper 操作 A:添加  U:更新  D:删除
         * @throws Exception
         */
        public void TryPushToCache(Object obj,String Oper) throws Exception
        {
            ECPDto dto=new ECPDto();
            dto.Cmd=Oper;
            dto.Model=obj.getClass().getSimpleName();
            dto.Data=JRT.Core.Util.JsonUtil.Object2Json(obj);
            //有事务就推缓存
            if(Hastransaction=true)
            {
                if(ToEcpTmp==null)
                {
                    ToEcpTmp=new ArrayList<>();
                }
                ToEcpTmp.add(dto);
            }
            else
            {
                //没事务的直接推入缓存队列
                JRT.DAL.ORM.Global.ECPManager.InECPToQuen(dto);
            }
        }
    
        /**
         * 为每个数据库驱动存储工厂
         */
        private static ConcurrentHashMap<String, IDbFactory> hsFact = new ConcurrentHashMap<>();
    
        /**
         * 为每个数据库驱动存储连接池
         */
        private static ConcurrentHashMap<String, ComboPooledDataSource> hsPoll = new ConcurrentHashMap<>();
    
        /**
         * 得到驱动对象
         * @param factoryName
         * @return
         */
        public IDbFactory GetIDbFactory(String factoryName)
        {
            if(factory==null)
            {
                factory=hsFact.get(factoryName);
            }
            return factory;
        }
    
    
        /**
         * 尝试初始化连接池
         * @param factoryName
         */
        public static void TryInitConnPool(String factoryName) throws Exception
        {
            if(factoryName=="")
            {
                factoryName="LisMianDbFactory";
            }
            if(!hsPoll.containsKey(factoryName))
            {
                IDbFactory factory=JRT.Core.Context.ObjectContainer.GetTypeObject(factoryName);
                hsPoll.put(factoryName,C3P0Util.GetConnPool(factory));
                if(!hsFact.containsKey(factoryName))
                {
                    hsFact.put(factoryName,factory);
                }
            }
        }
    
        /**
         * 构造函数
         * @param factName 驱动配置名称
         * @throws Exception
         */
        public DBManager(String factName) throws Exception
        {
            factoryName=factName;
            TryInitConnPool(factoryName);
        }
    
        /**
         * 存数据库连接对象
         */
        public Connection Connection() throws Exception
        {
            if(connection==null)
            {
                connection=hsPoll.get(factoryName).getConnection();
            }
            return connection;
        }
    
        /**
         * 标识是否开启事务
         */
        public boolean Hastransaction = false;
    
        /**
         * 存储开启多次事务的保存点,每次调用BeginTransaction开启事务是自动创建保存点
         */
        public LinkedList<Savepoint> Transpoints = new LinkedList<Savepoint>();
    
        /**
         * 获取开启的事务层级
         * @return
         */
        public int GetTransactionLevel()
        {
            return this.Transpoints.size();
        }
    
        /**
         * 释放数据库连接
         * @return true成功释放,false释放失败
         */
        public boolean Close() throws Exception
        {
            if(connection!=null)
            {
                connection.setAutoCommit(true);
                connection.close();
            }
            connection=null;
            return true;
        }
    
    
        /**
         * 此方法开启事务
         * @return  true开启事务成功,false开始事务失败
         */
        public boolean BeginTransaction() throws Exception
        {
            try
            {
                this.Connection().setAutoCommit(false);
                this.Hastransaction = true;
                Savepoint savepoint = this.Connection().setSavepoint();
                Transpoints.addLast(savepoint);
                return true;
            }
    
            catch (SQLException sqle)
            {
                JRT.Core.Util.LogUtils.WriteExceptionLog("开启事务失败!" + sqle.getMessage(), sqle);
            }
            return false;
        }
    
        /**
         * 回滚上一层事务
         * @return true回滚事务成功,false回滚事务失败
         */
        public boolean RollTransaction() throws Exception
        {
            //删除临时数据
            if(ToEcpTmp!=null) {
                ToEcpTmp.clear();
                ToEcpTmp=null;
            }
            //未开启事务时,算回滚事务成功
            if (!this.Hastransaction)
            {
                return true;
            }
            try
            {
                if (this.Transpoints.size() == 0)
                {
                    this.Connection().rollback();
                    this.Hastransaction = false;
                }
                else
                {
                    Savepoint point = this.Transpoints.poll();
                    this.Connection().rollback(point);
                }
                return true;
            }
            catch (SQLException sqle)
            {
                JRT.Core.Util.LogUtils.WriteExceptionLog("事务回滚失败!" + sqle.getMessage(),sqle);
                throw sqle;
            }
            finally
            {
                if (!this.Hastransaction)
                {
                    Close();
                }
            }
        }
    
        /**
         * 回滚开启的全部事务
         * @return true回滚事务成功,false回滚事务失败
         */
        public boolean RollTransactionAll() throws Exception
        {
            //删除临时数据
            if(ToEcpTmp!=null) {
                ToEcpTmp.clear();
                ToEcpTmp=null;
            }
            //未开启事务时,算回滚事务成功
            if (!this.Hastransaction)
            {
                return true;
            }
            try
            {
                this.Connection().rollback();
                this.Hastransaction = false;
                return true;
            }
            catch (SQLException sqle)
            {
                JRT.Core.Util.LogUtils.WriteExceptionLog("回滚所有事务层级失败!" + sqle.getMessage(),sqle);
                throw sqle;
            }
            finally
            {
                Close();
            }
        }
    
        /**
         * 提交事务
         * @return true提交事务成功,false提交事务失败
         */
        public boolean CommitTransaction() throws Exception
        {
            try
            {
                //临时数据推入缓存
                if(ToEcpTmp!=null)
                {
                    for(ECPDto obj:ToEcpTmp)
                    {
                        //没事务的直接推入缓存队列
                        JRT.DAL.ORM.Global.ECPManager.InECPToQuen(obj);
                    }
                }
                this.Connection().commit();
                this.Hastransaction = false;
                return true;
            }
            catch (SQLException sqle)
            {
                JRT.Core.Util.LogUtils.WriteExceptionLog("提交事务失败!" + sqle.getMessage(),sqle);
            }
            finally
            {
                //提交事务,不论成功与否,释放数据库连接
                try
                {
                    Close();
                }
                catch (Exception ex)
                {
    
                }
            }
            return false;
        }
    
    }
    
    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318

    增加的配置
    在这里插入图片描述

    这样就有一个理论上比较靠谱的缓存机制了,业务用SQL查到主列表数据后,调用DolerGet的获得各种周边相关数据来组装给前台返回,就不用每个写业务的人自己考虑写复杂的级联查询数据库受不了,自己缓存数据时候缓存是否可靠,自己不缓存数据时候调用太多数据库交互又慢的问题。DolerGet基本可以满足比较无脑的多维取数据组装的要求。

  • 相关阅读:
    alginate-Ferrocene|海藻酸钠-二茂铁|二茂铁修饰改性海藻酸钠|海藻酸钠-peg-二茂铁
    Spring Cloud Gateway实现数字签名与URL动态加密
    Spring Boot单元测试
    iptables的一次修复日志
    spring cloud 集成sentinel 报错 Failed to introspect Class
    【王道代码】【2.3链表】d3
    滴滴线下仿真环境实践:从方案设计到持续运营
    C++ string类模板
    物联网设备WIFI模块实现
    【linux】日志和journalctl 管理查看日志
  • 原文地址:https://blog.csdn.net/zhanglianzhu_91/article/details/134695655