Bạn có thể chọn giữa 3 chiến lược khác nhau sẽ ảnh hưởng đến việc thăm dò kết nối. Trong mọi trường hợp, bạn phải cung cấp triển khai MultiTenantConnectionProvider
. Chiến lược bạn chọn tất nhiên sẽ ảnh hưởng đến việc triển khai của bạn.
Nhận xét chung về MultiTenantConnectionProvider.getAnyConnection()
getAnyConnection()
được yêu cầu bởi chế độ ngủ đông để thu thập siêu dữ liệu và thiết lập SessionFactory. Thông thường trong kiến trúc nhiều đối tượng thuê, bạn có một cơ sở dữ liệu đặc biệt / chính (hoặc lược đồ) không được sử dụng bởi bất kỳ đối tượng thuê nào. Đó là một loại cơ sở dữ liệu mẫu (hoặc lược đồ). Sẽ ổn nếu phương thức này trả về một kết nối đến cơ sở dữ liệu này (hoặc lược đồ).
Chiến lược 1:mỗi người thuê có cơ sở dữ liệu riêng. (và vì vậy nó là nhóm kết nối riêng)
Trong trường hợp này, mỗi người thuê có nhóm kết nối riêng do C3PO quản lý và bạn có thể cung cấp triển khai MultiTenantConnectionProvider
dựa trên AbstractMultiTenantConnectionProvider
Mỗi người thuê đều có C3P0ConnectionProvider
của riêng mình , vì vậy tất cả những gì bạn phải làm trong selectConnectionProvider(tenantIdentifier)
là trả lại một trong những chính xác. Bạn có thể giữ một Bản đồ để lưu vào bộ nhớ cache của chúng và bạn có thể khởi tạo một cách lười biếng C3POConnectionProvider với một cái gì đó như:
private ConnectionProvider lazyInit(String tenantIdentifier){
C3P0ConnectionProvider connectionProvider = new C3P0ConnectionProvider();
connectionProvider.configure(getC3POProperties(tenantIdentifier));
return connectionProvider;
}
private Map getC3POProperties(String tenantIdentifier){
// here you have to get the default hibernate and c3po config properties
// from a file or from Spring application context (there are good chances
// that those default properties point to the special/master database)
// and alter them so that the datasource point to the tenant database
// i.e. : change the property hibernate.connection.url
// (and any other tenant specific property in your architecture like :
// hibernate.connection.username=tenantIdentifier
// hibernate.connection.password=...
// ...)
}
Chiến lược 2:mỗi đối tượng thuê có lược đồ riêng và nhóm kết nối riêng trong một cơ sở dữ liệu duy nhất
Trường hợp này rất giống với chiến lược đầu tiên liên quan đến ConnectionProvider
triển khai vì bạn cũng có thể sử dụng AbstractMultiTenantConnectionProvider
làm lớp cơ sở để triển khai MultiTenantConnectionProvider
của bạn
Việc triển khai rất giống với cách triển khai được đề xuất cho Chiến lược 1 ngoại trừ việc bạn phải thay đổi lược đồ thay vì cơ sở dữ liệu trong cấu hình c3po
Chiến lược 3:mỗi người thuê có giản đồ riêng trong một cơ sở dữ liệu duy nhất nhưng sử dụng nhóm kết nối được chia sẻ
Trường hợp này hơi khác vì mọi người thuê sẽ sử dụng cùng một nhà cung cấp kết nối (và do đó nhóm kết nối sẽ được chia sẻ). Trong trường hợp:nhà cung cấp kết nối phải đặt lược đồ để sử dụng trước khi sử dụng kết nối. tức là bạn phải triển khai MultiTenantConnectionProvider.getConnection(String tenantIdentifier)
(tức là triển khai mặc định được cung cấp bởi AbstractMultiTenantConnectionProvider
sẽ không hoạt động).
Với postgresql, bạn có thể làm điều đó với:
SET search_path to <schema_name_for_tenant>;
hoặc sử dụng bí danh
SET schema <schema_name_for_tenant>;
Vì vậy, đây là nội dung getConnection(tenant_identifier);
của bạn sẽ giống như sau:
@Override
public Connection getConnection(String tenantIdentifier) throws SQLException {
final Connection connection = getAnyConnection();
try {
connection.createStatement().execute( "SET search_path TO " + tenanantIdentifier );
}
catch ( SQLException e ) {
throw new HibernateException(
"Could not alter JDBC connection to specified schema [" +
tenantIdentifier + "]",
e
);
}
return connection;
}
Tham khảo hữu ích ở đây (tài liệu chính thức)
Liên kết hữu ích khác C3POConnectionProvider.java
Bạn có thể kết hợp chiến lược 1 và chiến lược 2 trong quá trình thực hiện của mình. Bạn chỉ cần một cách để tìm các thuộc tính kết nối / url kết nối chính xác cho đối tượng thuê hiện tại.
CHỈNH SỬA
Tôi nghĩ rằng lựa chọn giữa chiến lược 2 hoặc 3 phụ thuộc vào lưu lượng truy cập và số lượng người thuê trên ứng dụng của bạn. Với các nhóm kết nối riêng biệt:số lượng kết nối có sẵn cho một người thuê sẽ thấp hơn nhiều và vì vậy:nếu vì lý do hợp pháp nào đó mà một người thuê đột ngột cần nhiều kết nối, hiệu suất mà người thuê cụ thể này nhìn thấy sẽ giảm đáng kể (trong khi người thuê nhà khác sẽ không bị ảnh hưởng).
Mặt khác, với chiến lược 3, nếu vì một lý do chính đáng nào đó mà một người thuê đột nhiên cần nhiều kết nối:hiệu suất mà mọi người thuê nhìn thấy sẽ giảm xuống.
Nói chung, tôi nghĩ rằng chiến lược 2 linh hoạt và an toàn hơn:mọi người thuê không được sử dụng nhiều hơn một lượng kết nối nhất định (và số lượng này có thể được định cấu hình cho mỗi người thuê nếu bạn cần)