Java.util.Date
vs Java.sql.Date
: quand utiliser lequel et pourquoi?
Félicitations, vous avez frappé ma bête noire préférée avec JDBC: Gestion des cours de date.
Fondamentalement, les bases de données supportent généralement au moins trois formes de champs de date/heure qui sont la date, l'heure et l'horodatage. Chacun de ceux-ci a une classe correspondante dans JDBC et chacun d'eux s'étend Java.util.Date
. La sémantique rapide de chacun de ces trois est la suivante:
Java.sql.Date
correspond à SQL DATE, ce qui signifie qu'il stocke années, mois et jours tandis que heure, minute, seconde et milliseconde sont ignorés. De plus, _sql.Date
_ n'est pas lié aux fuseaux horaires.Java.sql.Time
correspond à SQL TIME et, comme il est évident, ne contient que des informations sur heure, minutes, secondes et millisecondes.Java.sql.Timestamp
correspond à SQL TIMESTAMP, qui correspond à une date exacte à la nanoseconde (notez que _util.Date
_ ne prend en charge que des millisecondes!) avec une précision personnalisable. L'un des problèmes les plus courants lors de l'utilisation de pilotes JDBC par rapport à ces trois types est que les types sont mal gérés. Cela signifie que _sql.Date
_ est spécifique à un fuseau horaire, _sql.Time
_ contient l'année, le mois et le jour en cours, et cetera et cetera.
Dépend du type SQL du champ, vraiment. PreparedStatement
a des réglages pour les trois valeurs, #setDate()
étant celui de _sql.Date
_, #setTime()
pour _sql.Time
_ et #setTimestamp()
pour _sql.Timestamp
_ .
Notez que si vous utilisez ps.setObject(fieldIndex, utilDateObject);
, vous pouvez réellement donner un _util.Date
_ normal à la plupart des pilotes JDBC qui le dévoreront comme s'il était du type correct, mais lorsque vous demanderez les données par la suite, vous remarquerez peut-être que vous manquez des choses.
Ce que je suis en train de dire qui économise les millisecondes/nanosecondes sous forme de texte normal et les convertit en tous les objets que vous utilisez (plugin joda-time obligatoire). Une solution simple consiste à stocker le composant de date sous la forme d'un composant long et le composant l'un par rapport à l'autre, par exemple actuellement, il s'agirait des valeurs 20100221 et 154536123. Ces nombres magiques peuvent être utilisés dans des requêtes SQL et seront portables d'une base de données à une autre. vous permettra d'éviter cette partie de l'API JDBC/Java Date: s entièrement.
LATE EDIT: À partir de Java 8, vous ne devez utiliser ni _Java.util.Date
_ ni _Java.sql.Date
_ si vous le pouvez à tous l'évitent et préfèrent utiliser plutôt le package Java.time
(basé sur Joda) plutôt que toute autre chose. Si vous n'êtes pas sur Java 8, voici la réponse d'origine:
Java.sql.Date
- lorsque vous appelez des méthodes/constructeurs de bibliothèques qui l'utilisent (comme JDBC). Pas autrement. Vous ne souhaitez pas introduire de dépendances dans les bibliothèques de bases de données pour des applications/modules qui ne traitent pas explicitement de JDBC.
Java.util.Date
- lors de l'utilisation de bibliothèques qui l'utilisent. Sinon, le moins possible, pour plusieurs raisons:
Il est modifiable, ce qui signifie que vous devez en faire une copie défensive chaque fois que vous le transmettez ou que vous le renvoyez depuis une méthode.
Il ne gère pas très bien les dates, ce qui fait que les personnes rétrogrades comme le vôtre pensent que les cours de manipulation des dates devraient l'être.
Maintenant, parce que j.u.D ne fait pas très bien son travail, les classes horribles Calendar
ont été introduites. Ils sont également instables et difficiles à utiliser. Ils doivent être évités si vous n’avez pas le choix.
Il existe de meilleures alternatives, comme Joda Time API (qui pourrait même le rendre dans Java 7 et devenir la nouvelle API officielle de traitement des dates - un recherche rapide dit que ce ne sera pas).
Si vous croyez qu'il est exagéré d'introduire une nouvelle dépendance comme Joda, long
s ne sont pas si mauvais à utiliser pour les champs d'horodatage dans les objets, bien que je les ai moi-même généralement enveloppés dans un texte lorsque je les distribue, pour des raisons de sécurité et Documentation.
Le seul moment pour utiliser Java.sql.Date
est dans un PreparedStatement.setDate
. Sinon, utilisez Java.util.Date
. Il est révélateur que ResultSet.getDate
renvoie un Java.sql.Date
mais il peut être affecté directement à un Java.util.Date
.
J'ai eu le même problème, la façon la plus simple que j'ai trouvée d'insérer la date du jour dans une déclaration préparée est la suivante:
preparedStatement.setDate(1, new Java.sql.Date(new Java.util.Date().getTime()));
La classe Java.util.Date dans Java représente un moment particulier (p. Ex., 25 nov. 2013, 16:30:45 en millisecondes), mais le type de données DATE dans le DB représente une date seulement (par exemple, le 25 novembre 2013). Pour vous empêcher de fournir par erreur un objet Java.util.Date à la base de données, Java ne vous permet pas de définir directement un paramètre SQL sur Java.util.Date:
PreparedStatement st = ...
Java.util.Date d = ...
st.setDate(1, d); //will not work
Mais cela vous permet toujours de le faire par force/intention (les heures et les minutes seront alors ignorées par le pilote de la base de données). Ceci est fait avec la classe Java.sql.Date:
PreparedStatement st = ...
Java.util.Date d = ...
st.setDate(1, new Java.sql.Date(d.getTime())); //will work
Un objet Java.sql.Date peut stocker un moment dans le temps (il est donc facile de construire à partir d'un fichier Java.util.Date), mais émettra une exception si vous essayez de lui demander le nombre d'heures (pour appliquer son concept de date seulement). Le pilote de base de données doit reconnaître cette classe et utiliser simplement 0 pour les heures. Essaye ça:
public static void main(String[] args) {
Java.util.Date d1 = new Java.util.Date(12345);//ms since 1970 Jan 1 midnight
Java.sql.Date d2 = new Java.sql.Date(12345);
System.out.println(d1.getHours());
System.out.println(d2.getHours());
}