會話(Session)


會話是對應用程式中特定業務操作觸發的一系列與資料庫之間的互動過程的封裝,透過建立一個臨時通道,負責與資料庫之間連接資源的建立及回收,同時提供更為高階的抽象指令介面調用,基於會話的優點:

開發人員不需要擔心連接資源是否正確釋放;

嚴格的編碼規範更利於維護和理解;

更好的業務封裝性;

  • 會話物件參數:

    • 資料庫連線持有者(IConnectionHolder) :

      指定本次會話所使用的資料來源連線;

    • 會話執行器(ISessionExecutor):

      以內部類別的形式定義本次會話傳回結果物件並提供Session實例物件的參考;

  • 開啟會話範例程式碼:

    ##
    // 使用默认数据源开启会话
    User _result = JDBC.get().openSession(new ISessionExecutor<User>() {
        public User execute(ISession session) throws Exception {
            // TODO 此处填写业务逻辑代码
            return session.findFirst(EntitySQL.create(User.class));
        }
    });
    
    // 使用指定的数据源开启会话
    IConnectionHolder _conn = JDBC.get().getConnectionHolder("oracledb");
    // 不需要关心_conn对象的资源释放
    IResultSet<User> _results = JDBC.get().openSession(_conn, new ISessionExecutor<IResultSet<User>>() {
        public IResultSet<User> execute(ISession session) throws Exception {
            // TODO 此处填写业务逻辑代码
            return session.find(EntitySQL.create(User.class));
        }
    });
  • #基於ISession介面的資料庫操作:

    範例程式碼是圍繞著使用者(User)資料實體完成的CRUD(新增、查詢、修改、刪除)操作來展示如何使用ISession對象,資料實體如下:

        @Entity("user")
        public static class User extends BaseEntity<User, String> {
    
            @Id
            @Property
            private String id;
    
            @Property(name = "user_name")
            private String username;
    
            @Property(name = "pwd")
            private String pwd;
    
            @Property(name = "sex")
            private String sex;
    
            @Property(name = "age")
            private Integer age;
    
            // 忽略Getter和Setter方法
    
            public static class FIELDS {
                public static final String ID = "id";
                public static final String USER_NAME = "username";
                public static final String PWD = "pwd";
                public static final String SEX = "sex";
                public static final String AGE = "age";
            }
            public static final String TABLE_NAME = "user";
        }
    • #插入(Insert):

      User _user = new User();
      _user.setId(UUIDUtils.UUID());
      _user.setUsername("suninformation");
      _user.setPwd(DigestUtils.md5Hex("123456"));
      _user.setAge(20);
      _user.setSex("F");
      // 执行数据插入
      session.insert(_user);
      
      // 或者在插入时也可以指定/排除某些字段
      session.insert(_user, Fields.create(User.FIELDS.SEX, User.FIELDS.AGE).excluded(true));
    • 更新(Update):

      User _user = new User();
      _user.setId("bc19f5645aa9438089c5e9954e5f1ac5");
      _user.setPwd(DigestUtils.md5Hex("654321"));
      // 更新指定的字段
      session.update(_user, Fields.create(User.FIELDS.PWD));
    • 查詢(Find):

      • 方式一:透過資料實體設定條件(非空屬性之間將使用and條件連接),查詢所有符合條件的記錄;

        User _user = new User();
        _user.setUsername("suninformation");
        _user.setPwd(DigestUtils.md5Hex("123456"));
        // 返回所有字段
        IResultSet<User> _users = session.find(_user);
        // 或者返回指定的字段
        _users = session.find(_user, Fields.create(User.FIELDS.ID, User.FIELDS.AGE));
      • 方式二:透過自訂條件,查詢所有符合條件的記錄;

        IResultSet<User> _users = session.find(
                EntitySQL.create(User.class)
                        .field(User.FIELDS.ID)
                        .field(User.FIELDS.SEX), 
                // 设置Order By条件
                Where.create()
                        .orderDesc(User.FIELDS.USER_NAME));
      • 方式三:分頁查詢;

        IResultSet<User> _users = session.find(
                EntitySQL.create(User.class)
                        .field(User.FIELDS.ID)
                        .field(User.FIELDS.SEX),
                Where.create()
                        .orderDesc(User.FIELDS.USER_NAME),
                // 查询第1页,每页10条记录,统计总记录数
                Page.create(1).pageSize(10).count(true));
      • #方式四:只傳回符合條件的第一筆記錄(FindFirst);

        // 查询用户名称和密码都匹配的第一条记录
        User _user = session.findFirst(EntitySQL.create(User.class), 
                Where.create(
                        Cond.create()
                                .eq(User.FIELDS.USER_NAME).param("suninformation")
                                .eq(User.FIELDS.PWD).param(DigestUtils.md5Hex("123456"))));

      :更多的查詢方式將在後面的「查詢(Query)」章節中詳細闡述;

    • 刪除(Delete):

      • #根據實體主鍵刪除記錄:

        User _user = new User();
        _user.setId("bc19f5645aa9438089c5e9954e5f1ac5");
        //
        session.delete(_user);
        
        //
        session.delete(User.class, "bc19f5645aa9438089c5e9954e5f1ac5");
      • 根據條件刪除記錄:

        // 删除年龄小于20岁的用户记录
        session.executeForUpdate(
                SQL.create(
                        Delete.create(User.class).where(
                                Where.create(
                                        Cond.create()
                                                .lt(User.FIELDS.AGE).param(20)))));
    • ##。 (Count):
    •     // 统计年龄小于20岁的用户记录总数
      
          // 方式一:
          long _count = session.count(User.class, 
                  Where.create(
                          Cond.create()
                                  .lt(User.FIELDS.AGE).param(20)));
      
          // 方式二:
          _count = session.count(
                  SQL.create(
                          Delete.create(User.class).where(
                                  Where.create(
                                          Cond.create()
                                                  .lt(User.FIELDS.AGE).param(20)))));
    • #執行更新類別操作(ExecuteForUpdate):
    • 此方法用於執行ISession接口中並未提供對應的方法封裝且執行操作會對資料庫產生變化的SQL語句,執行該方法後將傳回受影響記錄行數,如上方執行的刪除年齡小於20歲的使用者記錄:

          int _effectCount =session.executeForUpdate(
                  SQL.create(
                          Delete.create(User.class).where(
                                  Where.create(
                                          Cond.create()
                                                  .lt(User.FIELDS.AGE).param(20)))));

    :以上操作皆支援批次操作,具體使用請閱讀API介面文件與相關原始碼;