Oracle
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Oracle

Sự cố chuyển đổi Oracle SQL DATE bằng iBATIS qua Java JDBC

Thông tin đầy đủ (và nó phức tạp hơn so với mô tả ở đây và có thể phụ thuộc vào phiên bản cụ thể của trình điều khiển Oracle đang được sử dụng) nằm trong câu trả lời của Richard Yee tại đây - [liên kết tới Nabble hiện đã hết hạn]

Nhanh chóng lấy trước khi hết hạn từ nabble ...

Roger, Xem:http://www.oracle.com/technetwork/database/enterprise-edition/jdbc-faq-090281.html#08_01

Cụ thể:Các kiểu dữ liệu đơn giản Điều gì đang xảy ra với DATE và TIMESTAMP? Phần này dành cho các kiểu dữ liệu đơn giản. :-)

Trước 9.2, trình điều khiển JDBC của Oracle đã ánh xạ kiểu SQL DATE thành java.sql.Timestamp. Điều này có ý nghĩa nhất định vì kiểu SQL DATE của Oracle chứa cả thông tin ngày và giờ cũng như java.sql.Timestamp. Việc ánh xạ rõ ràng hơn tới java.sql.Date hơi có vấn đề vì java.sql.Date không bao gồm thông tin thời gian. Cũng có trường hợp RDBMS không hỗ trợ kiểu SQL TIMESTAMP, vì vậy không có vấn đề gì với việc ánh xạ DATE thành Dấu thời gian.

Trong 9.2, hỗ trợ TIMESTAMP đã được thêm vào RDBMS. Sự khác biệt giữa DATE và TIMESTAMP là TIMESTAMP bao gồm nano giây và DATE thì không. Vì vậy, bắt đầu từ 9.2, DATE được ánh xạ thành Ngày và TIMESTAMP được ánh xạ tới Dấu thời gian. Rất tiếc, nếu bạn đang dựa vào các giá trị DATE để chứa thông tin thời gian thì đã xảy ra sự cố.

Có một số cách để giải quyết vấn đề này:

Thay đổi các bảng của bạn để sử dụng TIMESTAMP thay vì DATE. Điều này có lẽ hiếm khi xảy ra, nhưng đó là giải pháp tốt nhất khi đúng như vậy.

Thay đổi ứng dụng của bạn để sử dụng defineColumnType để xác định các cột là TIMESTAMP thay vì DATE. Có một số vấn đề xảy ra với điều này vì bạn thực sự không muốn sử dụng defineColumnType trừ khi bạn phải sử dụng (xem defineColumnType là gì và khi nào tôi nên sử dụng nó?).

Thay đổi ứng dụng của bạn để sử dụng getTimestamp thay vì getObject. Đây là một giải pháp tốt khi có thể, tuy nhiên nhiều ứng dụng chứa mã chung dựa vào getObject, vì vậy không phải lúc nào cũng có thể thực hiện được.

Đặt thuộc tính kết nối V8Comp Tương thích. Điều này yêu cầu trình điều khiển JDBC sử dụng ánh xạ cũ thay vì ánh xạ mới. Bạn có thể đặt cờ này làm thuộc tính kết nối hoặc thuộc tính hệ thống. Bạn đặt thuộc tính kết nối bằng cách thêm nó vào đối tượng java.util.Properties được chuyển tới DriverManager.getConnection hoặc OracleDataSource.setConnectionProperties. Bạn đặt thuộc tính hệ thống bằng cách bao gồm tùy chọn -D trong dòng lệnh java của mình.

java -Doracle.jdbc.V8Comp Tương thích ="true" MyAppOracle JDBC 11.1 khắc phục sự cố này. Bắt đầu với bản phát hành này, trình điều khiển ánh xạ các cột SQL DATE thành java.sql.Timestamp theo mặc định. Không cần thiết lập V8Comp Tương thích để có được ánh xạ chính xác. V8Comp Tương thích hoàn toàn không được chấp nhận. Bạn hoàn toàn không nên sử dụng nó. Nếu bạn đặt nó thành true, nó sẽ không ảnh hưởng gì, nhưng bạn nên ngừng sử dụng nó.

Mặc dù nó hiếm khi được sử dụng theo cách đó, V8Comp Tương thích tồn tại không phải để khắc phục sự cố DATE to Date mà để hỗ trợ khả năng tương thích với cơ sở dữ liệu 8i. Cơ sở dữ liệu 8i (và cũ hơn) không hỗ trợ loại TIMESTAMP. Việc đặt V8Comp Tương thích không chỉ khiến SQL DATE được ánh xạ tới Dấu thời gian khi đọc từ cơ sở dữ liệu, nó còn khiến tất cả Dấu thời gian được chuyển đổi thành SQL DATE khi được ghi vào cơ sở dữ liệu. Vì 8i không được hỗ trợ, các trình điều khiển JDBC 11.1 không hỗ trợ chế độ tương thích này. Vì lý do này, V8Comp Tương thích không được hỗ trợ.

Như đã đề cập ở trên, trình điều khiển 11.1 theo mặc định chuyển đổi SQL DATE thành Dấu thời gian khi đọc từ cơ sở dữ liệu. Đây luôn là điều đúng đắn và việc thay đổi 9i là một sai lầm. Các trình điều khiển 11.1 đã trở lại hành vi đúng. Ngay cả khi bạn không đặt V8Comp Tương thích trong ứng dụng của mình, bạn sẽ không thấy bất kỳ sự khác biệt nào về hành vi trong hầu hết các trường hợp. Bạn có thể nhận thấy sự khác biệt nếu bạn sử dụng getObject để đọc cột DATE. Kết quả sẽ là Dấu thời gian thay vì Ngày. Vì Dấu thời gian là một lớp con của Ngày nên thường không phải là vấn đề. Nơi bạn có thể nhận thấy sự khác biệt là nếu bạn dựa vào chuyển đổi từ DATE thành Ngày để cắt ngắn thành phần thời gian hoặc nếu bạn thực hiện Chuỗi trên giá trị. Nếu không, thay đổi phải minh bạch.

Nếu vì lý do nào đó mà ứng dụng của bạn rất nhạy cảm với sự thay đổi này và bạn chỉ đơn giản phải có hành vi 9i-10g, thì có một thuộc tính kết nối mà bạn có thể đặt. Đặt mapDateToTimestamp thành false và trình điều khiển sẽ hoàn nguyên về hành vi mặc định 9i-10g và ánh xạ DATE đến Date.

Nếu có thể, bạn nên thay đổi loại cột của mình thành TIMESTAMP thay vì DATE.

-Richard

Roger Voss đã viết:Tôi đã đăng câu hỏi / vấn đề sau trên stackoverflow, vì vậy nếu ai đó biết cách giải quyết, rất vui khi xem nó được trả lời ở đó:

Sự cố chuyển đổi Oracle SQL DATE bằng iBATIS qua Java JDBC

Đây là mô tả sự cố:

Tôi hiện đang vật lộn với sự cố chuyển đổi Oracle sql DATE bằng iBATIS từ Java.

Đang sử dụng trình điều khiển mỏng Oracle JDBC ojdbc14 phiên bản 10.2.0.4.0. iBATIS phiên bản 2.3.2. Java 1.6.0_10-rc2-b32.

Sự cố xoay quanh một cột kiểu DATE đang được trả về bởi đoạn mã SQL này:

CHỌN * TỪ BẢNG (pk_invoice_qry.get_contract_rate (?,?,?,?,?,?,?,?,?,?)) Đặt hàng theo from_date

Lệnh gọi thủ tục gói trả về một con trỏ tham chiếu đang được bao bọc trong một BẢNG để sau đó dễ dàng đọc tập kết quả như thể là một truy vấn chọn đối với một bảng.

Trong PL / SQL Developer, một trong các cột được trả về, FROM_DATE, thuộc loại SQL DATE, có độ chính xác theo thời gian trong ngày:

Tue Dec 16 23:59:00 PST 2008

Nhưng khi tôi truy cập thông tin này qua iBATIS và JDBC, giá trị chỉ giữ lại độ chính xác cho đến ngày:

Tue Dec 16 12:00:00 AM PST 2008

Điều này rõ ràng hơn khi hiển thị như vậy:

Đáng lẽ phải là:1229500740000 mili giây kể từ epochTuesday, ngày 16 tháng 12 năm 2008 11:59:00 CH PST

Nhưng thay vào đó nhận được điều này:1229414400000 mili giây kể từ epochTuesday, ngày 16 tháng 12 năm 2008 12:00:00 SA PST (ví dụ như lớp java.sql.Date)

Cho dù tôi có thử gì đi nữa, tôi cũng không thể hiển thị độ chính xác đầy đủ của cột DATE này được trả về qua Java JDBC và iBATIS.

Cái mà iBATIS đang ánh xạ là cái này:

FROM_DATE:2008-12-03:lớp java.sql.Date

Ánh xạ iBATIS hiện tại là:

Tôi cũng đã thử:

hoặc

Nhưng tất cả các ánh xạ đã cố gắng đều mang lại cùng một giá trị Ngày bị cắt ngắn. Có vẻ như JDBC đã gây ra thiệt hại khi đánh mất độ chính xác của dữ liệu trước khi iBATIS chạm vào nó.

Rõ ràng là tôi đang mất một số độ chính xác dữ liệu của mình bằng cách chuyển qua JDBC và iBATIS mà điều này không xảy ra khi tôi ở trong PL / SQL Developer đang chạy cùng một đoạn mã SQL như một tập lệnh thử nghiệm. Không thể chấp nhận được chút nào, rất khó chịu và cuối cùng là rất đáng sợ.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Cách cài đặt song song ODP.NET 2.111 và ODP.NET 4.112 trong cùng một máy trong khi cả hai đều trỏ đến cùng một máy chủ cơ sở dữ liệu

  2. Kết nối chuỗi tổng hợp trong Oracle 10g

  3. Hàm NLS_CHARSET_ID () trong Oracle

  4. Ràng buộc các tham số truy vấn theo tên với ODP.NET

  5. Cách loại bỏ “X hàng đã chọn” trong SQLcl &SQL * Plus (Oracle)