Bạn có nên thiết lập thuộc tính kết nối cơ sở dữ liệu trong server.xml hoặc context.xml


79

Tôi đang cố gắng thiết lập thuộc tính kết nối cơ sở dữ liệu bằng JNDI cho ứng dụng web Spring.

Tôi đang xem xét hai cách tiếp cận như sau:

Phương pháp 1:

Trong cấu hình Spring của bạn, bạn có thể có những thứ như sau:

<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/facs"/>

Sau đó, trong tệp webapp /META-INF/context.xml của bạn, bạn cũng sẽ có một cái gì đó tương tự:

<?xml version='1.0' encoding='utf-8'?>

<!-- antiResourceLocking="true" -->
<Context path="/podd-apn"
         reloadable="true"
         cachingAllowed="false"
         antiResourceLocking="true"
         >

  <Resource name="jdbc/facs"              
            type="javax.sql.DataSource" username="${database.username}" password="${database.password}"
            driverClassName="org.postgresql.Driver" 
            url="${database.url}"
            maxActive="8" maxIdle="4"
            global="jdbc/facs" 
            />


</Context>

Và trong web.xml của bạn, bạn sẽ giống như sau:

<!-- JNDI -->
  <resource-ref>
    <description>FACs Datasource</description>
    <res-ref-name>jdbc/facs</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
  </resource-ref> 


Phương pháp 2:

Thiết lập trong bối cảnh Spring như sau:

<jee:jndi-lookup id="dbDataSource"
   jndi-name="jdbc/DatabaseName"
   expected-type="javax.sql.DataSource" />

Bạn có thể khai báo tài nguyên JNDI trong server.xml của Tomcat bằng cách sử dụng như sau:

<GlobalNamingResources>
  <Resource name="jdbc/DatabaseName" auth="Container" type="javax.sql.DataSource"
              username="dbUsername" password="dbPasswd"
              url="jdbc:postgresql://localhost/dbname"
              driverClassName="org.postgresql.Driver"
              initialSize="5" maxWait="5000"
              maxActive="120" maxIdle="5"
              validationQuery="select 1"
              poolPreparedStatements="true"/>
</GlobalNamingResources/>

Và tham khảo tài nguyên JNDI từ web context.xml của Tomcat như sau:

<ResourceLink name="jdbc/DatabaseName"
   global="jdbc/DatabaseName"
   type="javax.sql.DataSource"/>


Câu hỏi của tôi là đâu là nơi tốt nhất để giữ các thuộc tính cơ sở dữ liệu? Chúng nên được đặt trong server.xml hay context.xml ?

Ngoài ra, nếu tôi có 2 cơ sở dữ liệu, tôi có nên sử dụng hai cấu hình không?

Ngoài ra, cách tốt nhất là đặt trực tiếp chúng vào server.xml hoặc context.xml? Hay tôi cần cấu hình thông qua bảng điều khiển Tomcat Manager GUI?

Cảm ơn!

Câu trả lời:


27

Tôi thích cách tiếp cận thứ ba tận dụng tốt nhất từ Cách tiếp cận 1Cách tiếp cận 2 được mô tả bởi người dùng1016403 .

Phương pháp 3

  1. Lưu thuộc tính cơ sở dữ liệu trên server.xml
  2. tham chiếu các server.xmlthuộc tính cơ sở dữ liệu từ ứng dụng webMETA-INF/context.xml

Tiếp cận 3 lợi ích

Trong khi điểm đầu tiên hữu ích vì lý do bảo mật, điểm thứ hai hữu ích để tham chiếu giá trị thuộc tính máy chủ từ ứng dụng web, ngay cả khi giá trị thuộc tính máy chủ sẽ thay đổi.

Hơn nữa, việc tách các định nghĩa tài nguyên trên máy chủ khỏi việc sử dụng chúng bởi ứng dụng web làm cho cấu hình đó có thể mở rộng giữa các tổ chức với độ phức tạp khác nhau trong đó các nhóm khác nhau làm việc trên các tầng / lớp khác nhau: nhóm quản trị viên máy chủ có thể làm việc mà không xung đột với nhóm nhà phát triển nếu quản trị viên chia sẻ cùng Tên JNDI với nhà phát triển cho mỗi tài nguyên.

Phương pháp 3 thực hiện

Xác định tên JNDI jdbc/ApplicationContext_DatabaseName.

Khai báo jdbc/ApplicationContext_DatabaseNamecác thuộc tính và giá trị khác nhau của Tomcat server.xmlbằng cách sử dụng một cái gì đó như sau:

<GlobalNamingResources>
  <Resource name="jdbc/ApplicationContext_DatabaseName" auth="Container" type="javax.sql.DataSource"
              username="dbUsername" password="dbPasswd"
              url="jdbc:postgresql://localhost/dbname"
              driverClassName="org.postgresql.Driver"
              initialSize="5" maxWait="5000"
              maxActive="120" maxIdle="5"
              validationQuery="select 1"
              poolPreparedStatements="true"/>
</GlobalNamingResources/>

Liên kết các jdbc/ApplicationContext_DatabaseNamethuộc tính của từ ứng dụng web META-INF/context.xmlbằng ngữ cảnh JNDI dành riêng cho ứng dụng java:comp/env/được chỉ định trong namethuộc tính:

<Context path="/ApplicationContext" ... >
  <!--
    "global" attribute links to GlobalNamingResources in the ${catalina.base}/conf/server.xml (server administrator team)
    "name" attribute is relative to the application-private JNDI context java:comp/env/ and is looked up from the java web application (application developer team)
  -->
  <ResourceLink global="jdbc/ApplicationContext_DatabaseName" name="jdbc/DatabaseName" type="javax.sql.DataSource"/>
</Context>

Cuối cùng, để sử dụng tài nguyên JNDI, hãy chỉ định tên JNDI jdbc/DatabaseNametrong bộ mô tả triển khai của ứng dụng web:

<resource-ref>
    <description>DatabaseName's Datasource</description>
    <res-ref-name>jdbc/DatabaseName</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
</resource-ref> 

và trong bối cảnh mùa xuân:

<jee:jndi-lookup id="DatabaseNameDataSource"
   jndi-name="jdbc/DatabaseName"
   expected-type="javax.sql.DataSource" />

Tiếp cận 3 nhược điểm

Nếu tên JNDI bị thay đổi thì cả dấu server.xmlvà ý META-INF/context.xmlmuốn đều phải được chỉnh sửa và cần phải triển khai; tuy nhiên trường hợp này rất hiếm.

Tiếp cận 3 biến thể

Nhiều nguồn dữ liệu được sử dụng bởi một ứng dụng web

Chỉ cần thêm cấu hình vào Tomcat's server.xml:

<GlobalNamingResources>
  <Resource name="jdbc/ApplicationContext_DatabaseName1" ... />
  <Resource name="jdbc/ApplicationContext_DatabaseName2" ... />
  ...
</GlobalNamingResources/>

Thêm ứng dụng web liên kết META-INF/context.xmltheo ngữ cảnh JNDI dành riêng cho ứng dụng java:comp/env/được chỉ định trong namethuộc tính:

<Context path="/ApplicationContext" ... >
  <ResourceLink global="jdbc/ApplicationContext_DatabaseName1" name="jdbc/DatabaseName1" ... />
  <ResourceLink global="jdbc/ApplicationContext_DatabaseName2" name="jdbc/DatabaseName2" ... />
  ...
</Context>

Cuối cùng, thêm việc sử dụng tài nguyên JNDI trong bộ mô tả triển khai của ứng dụng web:

<resource-ref>
    <description>DatabaseName1's Datasource</description>
    <res-ref-name>jdbc/DatabaseName1</res-ref-name> ... 
</resource-ref> 
<resource-ref>
    <description>DatabaseName2's Datasource</description>
    <res-ref-name>jdbc/DatabaseName2</res-ref-name> ... 
</resource-ref>
...

và trong bối cảnh mùa xuân:

<jee:jndi-lookup id="DatabaseName1DataSource"
   jndi-name="jdbc/DatabaseName1" ... />
<jee:jndi-lookup id="DatabaseName2DataSource"
   jndi-name="jdbc/DatabaseName2" ... />
...


Nhiều nguồn dữ liệu được sử dụng bởi nhiều ứng dụng web trên cùng một máy chủ

Chỉ cần thêm cấu hình vào Tomcat's server.xml:

<GlobalNamingResources>
  <Resource name="jdbc/ApplicationContextX_DatabaseName1" ... />
  <Resource name="jdbc/ApplicationContextX_DatabaseName2" ... />
  <Resource name="jdbc/ApplicationContextY_DatabaseName1" ... />
  <Resource name="jdbc/ApplicationContextY_DatabaseName2" ... />
  ...
</GlobalNamingResources/>

cấu hình khác phải được suy ra từ trường hợp biến thể trước đó.


Nhiều nguồn dữ liệu đến cùng một cơ sở dữ liệu được sử dụng bởi nhiều ứng dụng web trên cùng một máy chủ

Trong trường hợp này, server.xmlcấu hình của Tomcat như:

<GlobalNamingResources>
  <Resource name="jdbc/ApplicationContextX_DatabaseName" ... />
  <Resource name="jdbc/ApplicationContextY_DatabaseName" ... />

kết thúc trong hai ứng dụng web khác nhau META-INF/context.xml như:

<Context path="/ApplicationContextX" ... >
  <ResourceLink global="jdbc/ApplicationContextX_DatabaseName" name="jdbc/DatabaseName" ... />
</Context>

và thích:

<Context path="/ApplicationContextY" ... >
  <ResourceLink global="jdbc/ApplicationContextY_DatabaseName" name="jdbc/DatabaseName" ... />
</Context>

vì vậy ai đó có thể lo lắng về thực tế name="jdbc/DatabaseName"là hai ứng dụng khác nhau được triển khai trên cùng một máy chủ tra cứu và sau đó sử dụng cùng một máy chủ: đây không phải là vấn đề vì đây jdbc/DatabaseNamelà ngữ cảnh JNDI riêng tư của ứng dụng java:comp/env/, vì vậy ApplicationContextX bằng cách sử dụngjava:comp/env/ không thể (theo thiết kế) tra cứu tài nguyên được liên kết với global="jdbc/ApplicationContextY_DatabaseName".

Tất nhiên nếu bạn cảm thấy thoải mái hơn mà không phải lo lắng về điều này, bạn có thể sử dụng một chiến lược đặt tên khác như:

<Context path="/ApplicationContextX" ... >
  <ResourceLink global="jdbc/ApplicationContextX_DatabaseName" name="jdbc/applicationXprivateDatabaseName" ... />
</Context>

và thích:

<Context path="/ApplicationContextY" ... >
  <ResourceLink global="jdbc/ApplicationContextY_DatabaseName" name="jdbc/applicationYprivateDatabaseName" ... />
</Context>

Câu hỏi liên quan đến tình huống "Nhiều nguồn dữ liệu cho cùng một cơ sở dữ liệu được sử dụng bởi nhiều ứng dụng web trên cùng một máy chủ" ... <Resource name="jdbc/ApplicationContextX_DatabaseName" ... /> <Resource name="jdbc/ApplicationContextY_DatabaseName" ... /> Nếu các tài nguyên là nhóm kết nối, điều này có cung cấp cho bạn hai nhóm riêng biệt, mỗi nhóm một ứng dụng web không? Trong khi, nếu tôi liên kết từ cả hai ứng dụng web với một tài nguyên, sẽ chỉ có một nhóm kết nối, đúng không? Bất kỳ lý do nào để thích cái này hơn cái kia? (nhóm kết nối DB riêng biệt một nhóm cho mỗi ứng dụng web so với một nhóm kết nối được chia sẻ bởi tất cả các ứng dụng web)? Cảm ơn.
Rebeccah

1
@Rebeccah - Q1: Nếu tài nguyên là nhóm kết nối, thì điều này có cung cấp cho bạn hai nhóm riêng biệt, một nhóm cho mỗi ứng dụng web không? A1: Có nó sẽ.
taringamberini

1
@Rebeccah - Câu hỏi 2: Trong khi đó, nếu tôi liên kết từ cả hai ứng dụng web với một tài nguyên, sẽ chỉ có một nhóm kết nối, đúng không? A2: Đúng.
taringamberini

2
@Rebeccah - Q3: Có lý do nào để thích cái này hơn cái kia không? (một nhóm kết nối DB riêng biệt cho mỗi ứng dụng web so với một nhóm kết nối được chia sẻ bởi tất cả các ứng dụng web)? A3: Tôi thích "nhóm kết nối DB riêng biệt, mỗi nhóm một ứng dụng web" bởi vì tôi không muốn rằng việc sử dụng nhiều webAppX sẽ dẫn đến sự chậm chạp của webAppY do cạn kiệt nhóm kết nối của webAppX; hơn nữa, hệ thống ghi nhật ký và giám sát cơ sở dữ liệu không thể phân biệt giữa các yêu cầu webAppX và webAppY, vì vậy việc hiểu và cách ly các vấn đề sẽ khó hoặc tệ hơn là không thể.
taringamberini

23

YOUR_APP.xml tập tin

Tôi thích Phương pháp tiếp cận 2 hơn (đặt mọi thứ (không chỉ một số thuộc tính trong cấu hình), nhưng thay vì đặt chúng trong toàn cục server.xmlhoặc toàn cục, context.xmlbạn nên đặt nó vào tệp dành riêng cho ứng dụng trong Tomcat của bạn.context.xml.default YOUR_APP.xml

Các YOUR_APP.xmltập tin nằm trong $catalinaHome/conf/<engine>/<host>(ví dụ conf/Catalina/localhost/YOUR_APP.xml).

Cấu hình trong ứng dụng cụ thể YOUR_APP.xmlchỉ có sẵn cho ứng dụng cụ thể.

Xem hướng dẫn do MuleSoft xuất bản. Và xem tài liệu chính thức, Tham khảo cấu hình Tomcat , trang cho Vùng chứa ngữ cảnh

Để trích dẫn tài liệu đó:

Các phần tử Ngữ cảnh riêng lẻ có thể được xác định rõ ràng:

•…

• Trong các tệp riêng lẻ (có phần mở rộng ".xml") trong $CATALINA_BASE/conf/[enginename]/[hostname]/thư mục. Đường dẫn ngữ cảnh và phiên bản sẽ được lấy từ tên cơ sở của tệp (tên tệp trừ phần mở rộng .xml).

•…


2
Cảm ơn câu trả lời của bạn. nếu tôi đặt tất cả các thuộc tính trong ứng dụng META-INF / context.xml của chúng tôi? nó là nơi tốt nhất để giữ?
user1016403

5
Tôi không nghĩ rằng việc đặt một số giá trị thuộc tính BÊN TRONG (đối với exampl trong META-INF / context.xml) ứng dụng là một cách tiếp cận tốt, vì sau đó bạn phải biên dịch lại và triển khai ứng dụng nếu các thuộc tính thay đổi. - Vì vậy, đây sẽ là gần giống như sử dụng không có tài sản ở tất cả và đặt các giá trị trực tiếp trong config.xml mùa xuân
Ralph

Sau đó, đâu là nơi được đề xuất để giữ chúng?
user1016403

2
Tôi chỉ cần thêm, thay vì xác định những điều này cho tất cả các ứng dụng bằng context.xml.default, bạn có thể sử dụng các tệp cấu hình ngữ cảnh dành riêng cho ứng dụng, như yourapp.xml trong cùng một thư mục, cho phép bạn chỉ hai triển khai của cùng một cuộc chiến tới cơ sở dữ liệu khác nhau.
usethe4ce

1
Không phải là một câu trả lời hữu ích. Nó chỉ nêu một sở thích và không đưa ra lời biện minh nào.
DavidS

10

Phương pháp 4

Thay vì sử dụng JNDI, tôi làm việc với .propertiescác tệp và xây dựng đối tượng phức tạp trong quá trình khởi tạo chương trình thay vì thời gian cấu hình.

Bạn đã sử dụng Spring và nó dễ dàng xây dựng DataSourcebằng cách:

<context:property-placeholder location="classpath:app.properties"/>

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="oracle.jdbc.OracleDriver"/>
    <property name="url" value="jdbc:oracle:thin:@${db.host}:${db.port}:${db.user}"/>
    <property name="username" value="${db.user}"/>
    <property name="password" value="${db.pass}"/>
</bean>

Tôi hoàn toàn đồng ý với Ralph với việc sử dụng bộ mô tả triển khai trong $CATALINA_BASE/conf/[enginename]/[hostname]/$APP.xmlnhưng thay vào đó là JNDI, tôi thích tệp khóa-giá trị thuần túy!

Với Spring, việc tiêm các thuộc tính trên vào các trường bean rất dễ dàng:

@Value("${db.user}") String defaultSchema;

thay vì JNDI:

@Inject ApplicationContext context;
Enviroment env = context.getEnvironment();
String defaultSchema = env.getProperty("db.user");

Cũng lưu ý rằng EL cho phép điều này (giá trị mặc định và thay thế đệ quy sâu):

@Value('${db.user:testdb}') private String dbUserName;

<property name='username' value='${db.user.${env}}'/>

Để ngoại hóa .propertiestệp, tôi sử dụng Tomcat 7 hiện đại có org.apache.catalina.loader.VirtualWebappLoader :

<Loader className="org.apache.catalina.loader.VirtualWebappLoader"
        virtualClasspath="/srv/web/app/"/>

Vì vậy, các nhà phát triển của bạn điền vào virtualClasspathcác đường dẫn đầy đủ bên ngoài cục bộ riêng biệt cho mỗi ứng dụng và đặt cục bộ app.propertiesvào dir đó.

Xem thêm:


0

Bạn cũng có thể sử dụng hỗ trợ URL JNDI cho các cấu hình ứng dụng khác nhau để kiểm tra, kiểm tra tích hợp, sản xuất.

<Context>
...
<Resource auth="Container" factory="com.benasmussen.jndi.url.URLFactory" 
name="url/MyUrl" type="java.net.URL" url="file:///your/path/to/file"/>
...
</Context>

<jee:jndi-lookup id="myUrl" jndi-name="java:comp/env/url/MyUrl" expected-type="java.net.URL" />

Kiểm tra dự án GitHub Hỗ trợ URL JNDI Tomcat để bật hỗ trợ URL JNDI cho các máy chủ Tomcat.


0

bước 1: context.xml

    <Context path="/projectname">
  <Resource auth="Container" 
            driverClassName="com.mysql.jdbc.Driver"
            logAbandoned="true" 
            maxActive="100" ``
            maxIdle="30" 
            maxWait="10000" 
            name="refname" 
            removeAbandoned="true" 
            removeAbandonedTimeout="60" 
            type="javax.sql.DataSource" 
            url="jdbc:mysql://localhost:8080/dbname" 
            username="root"
            password="root"/>
</Context>

Bước 2: web.xml

<resource-ref>
        <description>DB Connection</description>
        <res-ref-name>refname</res-ref-name>
        <res-type>javax.sql.DataSource</res-type>
        <res-auth>Container</res-auth>
    </resource-ref>

Bước 3: Tạo một lớp học để có kết nối

Connection connection = null;        
            Context context = (Context) new InitialContext().lookup("java:comp/env");
            DataSource ds = (DataSource) context.lookup("refname");
            connection = ds.getConnection();

Mọi thứ đã được thiết lập

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.