Java Swing 和 Postgres 用户身份验证 : Close old connection when new connection opened

标签 java postgresql connection singleton

我有一个 Java Swing 应用程序,它使用简单的单例模式访问 Postgres 数据库:

public class DatabaseConnection {
    private static final String uname = "*******";
    private static final String pword = "*******";
    private static final String url = "*******************************";

    Connection connection;
    // load jdbc driver
    public DatabaseConnection(){
        try{
            Class.forName("org.postgresql.Driver");
            establishConnection();
        } catch (ClassNotFoundException ce) {
            System.out.println("Could not load jdbc Driver: ");
            ce.printStackTrace();
        }
    }
    public Connection establishConnection() {
        // TODO Auto-generated method stub
        try{
            connection = DriverManager.getConnection(url, uname, pword);
        } catch (SQLException e){
            System.out.println("Could not connect to database: ");
            e.printStackTrace();
        }
        return connection;
    }
}

public class SingletonConnection {

    private static DatabaseConnection con;

    public SingletonConnection(){}

    public static DatabaseConnection instance(){

        assert con == null;
            con = new DatabaseConnection();
        return con;
    }
}

这是我由 Pgadmin3 创建的用户表(因此是丑陋的大写字母):

CREATE TABLE "user"
(
  id serial NOT NULL,
  "userRoleId" integer NOT NULL,
  "employeeId" bigint NOT NULL,
  "subjectId" bigint NOT NULL,
  username text NOT NULL,
  cryptpwd text NOT NULL,
  "userStatusId" integer NOT NULL,
  md5pwd text NOT NULL,
  CONSTRAINT pk_user PRIMARY KEY (id),
  CONSTRAINT "subjectId" FOREIGN KEY ("subjectId")
      REFERENCES subject (id) MATCH FULL
      ON UPDATE RESTRICT ON DELETE RESTRICT DEFERRABLE INITIALLY IMMEDIATE,
  CONSTRAINT user_employee_id FOREIGN KEY ("employeeId")
      REFERENCES employee (id) MATCH FULL
      ON UPDATE RESTRICT ON DELETE RESTRICT DEFERRABLE INITIALLY IMMEDIATE,
  CONSTRAINT "user_userRole_id" FOREIGN KEY ("userRoleId")
      REFERENCES "userRole" (id) MATCH FULL
      ON UPDATE RESTRICT ON DELETE RESTRICT DEFERRABLE INITIALLY IMMEDIATE,
  CONSTRAINT "user_userStatus_id" FOREIGN KEY ("userStatusId")
      REFERENCES "userStatus" (id) MATCH FULL
      ON UPDATE RESTRICT ON DELETE RESTRICT DEFERRABLE INITIALLY IMMEDIATE,
  CONSTRAINT "unique_user_userName" UNIQUE (username)
)

由于此应用程序将在本地网络中的许多计算机上运行,​​因此我希望每个特定用户只有一个连接实例。也就是说,如果 userA 从一台计算机登录,稍后 userA 从另一台计算机登录,则两台计算机上都应出现通知,并且第二个登录可以选择继续连接 - 在这种情况下,现有连接将被删除/丢失。

我想我必须在我的用户表中添加一个新列(logged_on boolean)...在这种情况下,第二次登录是通过查找logged_on的值并采取适当的行动来处理的。我的问题是,我如何才能关闭第一个连接?如何在数据库级别维持每个用户最多一个连接?

最佳答案

好的,这就是我正在做的事情。令人惊讶的是,我正在考虑一些与你提到的 Zamezela 类似的事情......我还没有让它工作,但我认为这应该工作。

我的用户表:

CREATE TABLE "user"
(
  id serial NOT NULL,
  "userRoleId" integer NOT NULL,
  "employeeId" bigint NOT NULL,
  "subjectId" bigint NOT NULL,
  username text NOT NULL,
  cryptpwd text NOT NULL,
  "userStatusId" integer NOT NULL,
  md5pwd text NOT NULL,
  "loggedIn" boolean NOT NULL DEFAULT false,
  CONSTRAINT pk_user PRIMARY KEY (id),
  CONSTRAINT "subjectId" FOREIGN KEY ("subjectId")
      REFERENCES subject (id) MATCH FULL
      ON UPDATE RESTRICT ON DELETE RESTRICT DEFERRABLE INITIALLY IMMEDIATE,
  CONSTRAINT user_employee_id FOREIGN KEY ("employeeId")
      REFERENCES employee (id) MATCH FULL
      ON UPDATE RESTRICT ON DELETE RESTRICT DEFERRABLE INITIALLY IMMEDIATE,
  CONSTRAINT "user_userRole_id" FOREIGN KEY ("userRoleId")
      REFERENCES "userRole" (id) MATCH FULL
      ON UPDATE RESTRICT ON DELETE RESTRICT DEFERRABLE INITIALLY IMMEDIATE,
  CONSTRAINT "user_userStatus_id" FOREIGN KEY ("userStatusId")
      REFERENCES "userStatus" (id) MATCH FULL
      ON UPDATE RESTRICT ON DELETE RESTRICT DEFERRABLE INITIALLY IMMEDIATE,
  CONSTRAINT "unique_user_userName" UNIQUE (username)
)

我创建了一个表来记录每个用户登录。将帮助追踪用户 Activity :

CREATE TABLE "userLoginHistory"
(
  "userId" integer NOT NULL,
  _datetime timestamp without time zone NOT NULL,
  hostname text NOT NULL,
  "osUsername" text NOT NULL,
  id bigserial NOT NULL,
  CONSTRAINT "pk_userLoginHistory" PRIMARY KEY (id),
  CONSTRAINT "userLoginHistory_user_id" FOREIGN KEY ("userId")
      REFERENCES "user" (id) MATCH FULL
      ON UPDATE RESTRICT ON DELETE RESTRICT DEFERRABLE INITIALLY IMMEDIATE
)

到目前为止,我现在拥有三个主要的存储功能......明天可能会添加它们。迟到了。

第一个涉及请求用户登录。这将返回用户 ID、角色、是否有人登录该用户帐户以及该用户是否处于 Activity 状态:

create type userLoginRequestReturnType as
(
  userId integer, -- user.id
  userRoleId integer, -- user.roleId
  loggedIn boolean, -- user.loggedIn
  userActive boolean -- whether user is active
);

CREATE OR REPLACE FUNCTION "user_login_request"(usernameIn text, passwordIn text)
returns setof userLoginRequestReturnType as
$$
declare
    user_Id integer;
    user_RoleId integer;
    user_StatusId integer;
    user_loggedIn boolean;
    user_Active boolean;

    sql text;
begin
      user_Active = false;
      select into user_Id, user_RoleId, user_StatusId, user_loggedIn id, "userRoleId", "userStatusId", "loggedIn" from "user" where username = usernameIn and cryptpwd = crypt(passwordIn, cryptpwd);
      if (user_id > 0) then -- record found
    select into user_Active "user_is_active"(user_StatusId);
      else
    user_id = 0;
    user_RoleId = 0;
    user_loggedIn = false;
    user_Active = false;
      end if;
      sql =  'select ' || user_Id || ', ' || user_RoleId || ', ' || user_loggedIn || ', ' || user_Active ||';';
      return query execute sql;
end;
$$ language 'plpgsql';

这被传递到前端。如果user_loggedIn为true,并且所有其他属性都支持成功登录,那么前端将通知用户存在现有连接,以及是否继续(断开现有连接)。如果为 false,则它只是继续(没有任何提示)到此函数:

CREATE OR REPLACE FUNCTION "user_login_complete"(userIdIN integer, hostnameIN text, osUsernameIN text)
returns bigint as
$$
declare
    currentTime timestamp without time zone;
    userLoginHistoryId bigint;
begin
      -- update user.loggedIn
      update "user" set "loggedIn" = true where id = userIdIN;
      -- insert into userLoginHistory
      currentTime = NOW()::timestamp without time zone;
      insert into "userLoginHistory" ("userId", _datetime, hostname, "osUsername") values (userIdIN, currentTime, hostnameIN, osUsernameIN);
      select into userLoginHistoryId currval('"userLoginHistory_id_seq"');
      return userLoginHistoryId;
end;
$$ language 'plpgsql';

userLoginHistoryId 存储在前端,因为我在 Java Swing 项目中使用 MVC 架构,所以我的抽象模型类将在其构造函数中调用以下函数。我已采纳您的建议,并将在每种方法中关闭连接。

-- function to check if the current logged in session is the last one recorded in database
-- to be run before each connection to the database as per userId
-- new userLoginHistoryId must be inserted into table userLoginHistory, and the id PK value stored in the front end
--
-- returns: true, if current session is the last session recorded in table userLoginHistory for this user_autosuggest_by_ID
--    : false, if another login session has been recorded.
-- MUST BE EXECUTED BEFORE EACH AND EVERY DATABASE TRANSACTION!!!!!
CREATE OR REPLACE FUNCTION "user_login_session_check"(userIdIN integer, userLoginHistoryIdIN bigint)
returns boolean as
$$
declare
    results boolean;
    userLoginHistoryId bigint;
begin
      results = true;
      select into userLoginHistoryId id from "userLoginHistory" where "userId" = userIdIN ORDER BY id DESC LIMIT 1;
      if (userLoginHistoryIdIN = userLoginHistoryId) then
    results = true;
      else
    results = false;
      end if;
end;
$$ language 'plpgsql';

明天进行测试,希望一切顺利。欢迎大家发表评论。

谢谢。

关于Java Swing 和 Postgres 用户身份验证 : Close old connection when new connection opened,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11153322/

相关文章:

sql - 结合 HABTM 的作用域和 belongs_to 与 OR 的关联

java - 检查 HttpServletRequest 的连接是否仍然打开?

Tomcat 6 忽略外部连接

java - 在java中查找字符串的所有大写字母

java - 如何知道两个线程中哪个线程先完成执行

java - 无法对非静态类型 T 进行静态引用

java - 在 Wildfly 9 上运行 Renjin Java-API

postgresql - 循环每个数组的项目 Postgresql

PHP ARRAY, 2 foreach, input name =""问题

java - MySQL连接在线数据库错误