Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/58.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Akka-Actor消息中的封闭逻辑_Java_Mysql_Akka_Actor_Slick - Fatal编程技术网

Java Akka-Actor消息中的封闭逻辑

Java Akka-Actor消息中的封闭逻辑,java,mysql,akka,actor,slick,Java,Mysql,Akka,Actor,Slick,我最近开始学习AKKA,我创建了一个路由器演员,有一群数据库工作者演员坐在路由器后面。我附带了这个实现,每个工作者参与者将有一个数据库连接,我通过实现接口SQLExecutable将数据库逻辑封装到每条消息中,参与者将执行每条消息。如果连接断开,异常将由路由器的监控策略处理 我的问题是,我知道AKKA中的每一条消息都应该是不可变的,在这里我将逻辑封装在消息中,我不确定这是否会导致任何意外行为。我的目的只是想将业务逻辑和数据库连接解耦 public class TokenRepository {

我最近开始学习AKKA,我创建了一个路由器演员,有一群数据库工作者演员坐在路由器后面。我附带了这个实现,每个工作者参与者将有一个数据库连接,我通过实现接口SQLExecutable将数据库逻辑封装到每条消息中,参与者将执行每条消息。如果连接断开,异常将由路由器的监控策略处理

我的问题是,我知道AKKA中的每一条消息都应该是不可变的,在这里我将逻辑封装在消息中,我不确定这是否会导致任何意外行为。我的目的只是想将业务逻辑和数据库连接解耦

public class TokenRepository {
private static final ActorSelection DB_ROUTER_SELECTION;
private static final String DB_ROUTER_SELECTION_PATH = "/user/JDBCRouter";
private static final int EXECUTE_TIME_OUT = 1000;
private static final String SAVE_TOKEN_STR = "INSERT INTO Tokens " +
        "(uuid, creation, email, expiration, isSignUp) " +
        "VALUES (?,?,?,?,?)";

private static final String FIND_TOKEN_STR = "SELECT * FROM Tokens " +
        "WHERE uuid = ?";

private static final String DELETE_TOKEN_STR = "DELETE FROM Tokens" +
        "WHERE uuid = ?";


static {
    DB_ROUTER_SELECTION = AkkaActorSystem.getInstance().actorSelection(DB_ROUTER_SELECTION_PATH);
}


private static class saveTokenExecutor implements SQLExecutable {
    private final Token token;

    saveTokenExecutor(Token token) {
        this.token = token;
    }

    @Override
    public void execute(Connection connection, UntypedActorContext untypedActorContext) throws SQLException {
        connection.setAutoCommit(false);
        java.sql.PreparedStatement preparedStatement = connection.prepareStatement(SAVE_TOKEN_STR);
        preparedStatement.setString(1, token.getUuid());
        preparedStatement.setTimestamp(2, new java.sql.Timestamp(token.getCreationTime().getMillis()));
        preparedStatement.setString(3, token.getEmail());
        preparedStatement.setTimestamp(4, new java.sql.Timestamp(token.getCreationTime().plusMinutes(5).getMillis()));
        preparedStatement.setBoolean(5, token.getIsSignUp());
        preparedStatement.execute();
        connection.commit();
        untypedActorContext.sender().tell(token, ActorRef.noSender());

    }
}

private static class findTokenExecutor implements SQLExecutable {
    private final String uuid;

    public findTokenExecutor(String uuid) {
        this.uuid = uuid;
    }

    @Override
    public void execute(Connection connection, UntypedActorContext untypedActorContext) throws SQLException {
        connection.setAutoCommit(false);
        java.sql.PreparedStatement preparedStatement = connection.prepareStatement(FIND_TOKEN_STR);
        preparedStatement.setString(1, uuid);
        preparedStatement.execute();
        ResultSet resultSet = preparedStatement.getResultSet();
        resultSet.next();
        Token token = new Token();
        token.setEmail(resultSet.getString("email"));
        token.setIsSignUp(resultSet.getBoolean("isSignUp"));
        token.setCreationTime(new DateTime(resultSet.getTimestamp("creation")));
        token.setExpirationTime(new DateTime(resultSet.getTimestamp("expiration")));
        token.setUuid(resultSet.getString("uuid"));
        connection.commit();
        untypedActorContext.sender().tell(token, ActorRef.noSender());
    }
}

private static class deleteTokenExecutor implements SQLExecutable {
    private final String uuid;

    public deleteTokenExecutor(String uuid) {
        this.uuid = uuid;
    }

    @Override
    public void execute(Connection connection, UntypedActorContext untypedActorContext) throws SQLException {
        java.sql.PreparedStatement preparedStatement = connection.prepareStatement(DELETE_TOKEN_STR);
        preparedStatement.setString(1, uuid);
    }
}

public static Future<Token> saveToken(Token token) {
    Future<Object> tokenFuture = ask(DB_ROUTER_SELECTION, new saveTokenExecutor(token), 1000);
    return tokenFuture.flatMap(new Mapper<Object, Future<Token>>() {
        @Override
        public Future<Token> apply(Object parameter) {
            return Futures.successful((Token) parameter);
        }
    }, AkkaActorSystem.getInstance().dispatcher());
}

public static Future<Token> findToken(String uuid) {
    Future<Object> tokenFuture = ask(DB_ROUTER_SELECTION, new findTokenExecutor(uuid), EXECUTE_TIME_OUT);
    return tokenFuture.flatMap(new Mapper<Object, Future<Token>>() {
        @Override
        public Future<Token> apply(Object parameter) {
            return Futures.successful((Token) parameter);
        }
    }, AkkaActorSystem.getInstance().dispatcher());

}

/**
 * delete token
 *
 * @param uuid
 * @return future<int>
 */
public static Future<Object> deleteToken(String uuid) {
    return ask(DB_ROUTER_SELECTION, new deleteTokenExecutor(uuid), EXECUTE_TIME_OUT);
}
}


}

这只是我的观点,但如果我是你,我会避免这样做。只是闻起来很怪。如果您确实需要这种基于命令模式的行为,那么您可以在请求消息和命令类之间创建一种关系,以便在收到这些请求时执行。这种解耦感觉更干净,但这完全是我的观点。我对如何在akka中处理数据库阻塞操作感到困惑,并且我没有找到很多关于这方面的好实践。所以我收集了一些想法并实施了一个解决方案@cmbaxter
public class DBWorker extends UntypedActor {
private final String host, user, password, db;
private final int port ;
private java.sql.Connection conn;

private static class DBWorkerCreator implements Creator<DBWorker> {
    private final String host, user, password, db;
    private final int port;

    public DBWorkerCreator(String host, int port, String user, String password, String db){
        this.host = host;
        this.user = user;
        this.port = port;
        this.password = password;
        this.db = db;
    }

    @Override
    public DBWorker create() throws Exception {
        return new DBWorker(host, port, user, password, db);
    }
}

public static Props getProps(String host, int port, String user, String password,String db){
    return Props.create(new DBWorkerCreator(host, port, user, password, db));
}

public DBWorker(String host, int port, String user, String password, String db){
    this.host = host;
    this.port = port;
    this.user = user;
    this.password = password;
    this.db = db;
}

/**
 * initialization: database connection
 */
@Override
public void preStart() throws Exception {
    try {
        String url = "jdbc:mysql://"+ host + ":" + port + "/" + db;
        System.out.println(url);
        conn = DriverManager.getConnection(url,user,password );
    } catch (SQLException e) {
        //something happens when connecting to the database, throw exception to DB Router
        e.printStackTrace();
        throw e;
    }
}


//cancel post start
@Override
public void postRestart(Throwable reason){

}

@Override
public void onReceive(Object message) throws Exception {


    try {
        if(message instanceof SQLExecutable){
            ((SQLExecutable) message).execute(conn,getContext());
        } else if (message instanceof String){
            conn.createStatement().execute((String)message);
        }
        else {
            // unknown message, do nothing here
        }
    } catch (SQLException e) {
        e.printStackTrace();

        try {
            //if SQLException is throwing up, rollback
            conn.rollback();
        } catch (SQLException e1) {
            // something serious happens, throw the exception to DB router
            e1.printStackTrace();
            throw e1;
        }

    } finally {

    }
}