ينفّذ
clickhouse-jdbc واجهة JDBC القياسية باستخدام أحدث عميل Java.
نوصي باستخدام أحدث عميل Java مباشرةً إذا كانت الأولوية القصوى للأداء أو للوصول المباشر.متطلبات البيئة
- OpenJDK الإصدار >= 8
الإعداد
- Maven
- Gradle (Kotlin)
- Gradle
- Maven Central ثم أضِفه إلى
classpath- بدءًا من الإصدار
0.9.4، تتوفر الحزمة https://mvnrepository.com/artifact/com.clickhouse/clickhouse-jdbc-all - استخدم اللاحقة
allللحصول على ملف jar يتضمن جميع التبعيات المدمجة.
- بدءًا من الإصدار
- أو من repository الرسمي هنا
الإعداد
فئة برنامج التشغيل:com.clickhouse.jdbc.ClickHouseDrivercom.clickhouse.jdbc.ClickHouseDriver هي فئة واجهة للإصدارين الجديد والقديم من JDBC. وتستخدم تنفيذ JDBC الجديد افتراضيًا.
يمكنك استخدام تنفيذ JDBC القديم من خلال تعيين خاصية system clickhouse.jdbc.v1 إلى true. ويجب تعيين هذه الخاصية قبل استدعاء
فئة Driver.والطريقة البديلة للتبديل بين الإصدارين هي استخدام فئات Driver الخاصة بكل إصدار مباشرةً:com.clickhouse.jdbc.Driverهو تنفيذ JDBC الجديد (V2).com.clickhouse.jdbc.DriverV1هو تنفيذ JDBC القديم (V1).
jdbc:(ch|clickhouse)[:<protocol>]://endpoint[:port][/<database>][?param1=value1¶m2=value2][#tag1,tag2,...]، على سبيل المثال:jdbc:clickhouse:http://localhost:8123jdbc:clickhouse:https://localhost:8443?ssl=true
- يُسمح بوجود نقطة نهاية واحدة فقط في URL
- يجب تحديد البروتوكول إذا لم يكن البروتوكول الافتراضي، وهو ‘HTTP’
- يجب تحديد المنفذ إذا لم يكن المنفذ الافتراضي ‘8123’
- لا يستنتج المُشغِّل البروتوكول من المنفذ، لذا يجب تحديده صراحةً
- لا تكون المعلَمة
sslمطلوبة عند تحديد البروتوكول.
خصائص الاتصال
تُعرَّف معاملات الإعداد الرئيسية في Java client، وينبغي تمريرها كما هي إلى driver. يمتلك driver بعض الخصائص الخاصة به التي لا تندرج ضمن إعداد client، وهي مُدرجة أدناه.خصائص برنامج التشغيل:مثال على الإعداد:
readonly=2.
اطّلع على مزيد من المعلومات حول ملفات التعريف للقراءة فقط هنا.تعريف العميل
ثمة طريقتان لتحديد التطبيق الذي أنشأ الطلب: ضبطcom.clickhouse.client.api.ClientConfigProperties#CLIENT_NAME عبر
خصائص الاتصال، أو استخدام الأسلوب java.sql.Connection#setClientInfo(String name, String value).showLineNumbers
showLineNumbers
http_user_agent في سجل الاستعلام:app_name/version للخاصية client_name لأنه يُساعد في التعرف على التطبيق في سجل الاستعلامات.تحديد العملية
يُنشئ JDBC driver معرّفquery_id لكل عملية (يُضمَّن حاليًا في استثناءات الخادم).لتعيين log_comment لعملية ما، استخدم الـ method com.clickhouse.jdbc.StatementImpl#getLocalSettings. يستلزم ذلك تحويل Statement أو PreparedStatement إلى النوع com.clickhouse.jdbc.StatementImpl أولاً.showLineNumbers
localSettings مشترك بين الخيوط.أنواع البيانات المدعومة
يدعم JDBC driver نفس تنسيقات البيانات التي يدعمها Java client الأساسي.تعيين أنواع JDBC
ينطبق التعيين التالي على:ResultSet#getObject(columnIndex)- تُعيد الطريقة كائنًا من فئة Java المقابلة. (Int8->java.lang.Byte,Int16->java.lang.Short, إلخ.)ResultSetMetaData#getColumnType(columnIndex)- تُعيد الطريقة نوع JDBC المقابل. (Int8->java.lang.Byte,Int16->java.lang.Short, إلخ.)
ResultSet#getObject(columnIndex, class)- ستحاول هذه الطريقة تحويل القيمة إلى النوعclass. توجد بعض القيود على هذا التحويل. راجع كل قسم للاطلاع على التفاصيل.
- الأنواع الرقمية قابلة للتحويل فيما بينها. لذا يمكن الحصول على
Int8بصيغةFloat64والعكس صحيح.:- سيُرجع
rs.getObject(1, Float64.class)قيمةFloat64منInt8column. - سيُرجع
rs.getLong(1)قيمةLongمنInt8column. - يمكن أن يُرجع
rs.getByte(1)قيمةByteمنInt16column إذا كانت ضمن نطاقByte.
- سيُرجع
- لا يُنصح بالتحويل من نوع أوسع إلى نوع أضيق بسبب خطر تلف البيانات.
- يتعامل النوع
Boolأيضًا على أنه عدد. - يمكن قراءة جميع الأنواع العددية على أنها
java.lang.String. - توجد مشكلة عند تخزين
Float.MAX_VALUEفي Java بوصفهFloat(https://github.com/ClickHouse/clickhouse-java/issues/809). ويؤدي حفظ القيمة نفسها بوصفهاDoubleإلى حل هذه المشكلة.
- لا يمكن قراءة
Stringإلا باعتبارهjava.lang.Stringأوbyte[]. - تُقرأ
FixedStringكما هي، وتُحشى بأصفار حتى يصل طولها إلى طول العمود. (على سبيل المثال، ستُقرأFixedString(10)للقيمة'John'على أنها'John\0\0\0\0\0\0\0\0\0'.)
- يُعيَّن
Enum8وEnum16إلىjava.lang.Stringافتراضيًا. - يمكن قراءة قيم Enum كقيم رقمية باستخدام دالة getter المخصّصة أو الدالة
getObject(columnIndex, Integer.class). - يُعيَّن
Enum16داخليًا إلى short، ويُعيَّنEnum8إلى byte. ويجب تجنّب قراءةEnum16على أنه byte بسبب خطر تلف البيانات. - يمكن تعيين قيم Enum كسلسلة نصية أو كقيمة رقمية في
PreparedStatement.
- تُطابَق أنواع
Date / Timeمع أنواعjava.sqlلتحسين التوافق مع JDBC. ومع ذلك، يمكن أيضًا الحصول علىjava.time.LocalDateوjava.time.LocalDateTimeوjava.time.LocalTimeباستخدامResultSet#getObject(columnIndex, Class<T>)مع تمرير الفئة المقابلة بوصفها الوسيط الثاني.- ستُعيد
rs.getObject(1, java.time.LocalDate.class)القيمةjava.time.LocalDateمن العمودDate. - ستُعيد
rs.getObject(1, java.time.LocalDateTime.class)القيمةjava.time.LocalDateTimeمن العمودDateTime. - ستُعيد
rs.getObject(1, java.time.LocalTime.class)القيمةjava.time.LocalTimeمن العمودTime.
- ستُعيد
- لا تتأثر
DateوDate32وTimeوTime64بالمنطقة الزمنية للخادم. - يتأثر
DateTimeوDateTime64بالمنطقة الزمنية للخادم أو بالمنطقة الزمنية للجلسة. - يمكن استرجاع
DateTimeوDateTime64كـZonedDateTimeباستخدامgetObject(colIndex, ZonedDateTime.class).
- يُعيَّن
Arrayإلىjava.sql.Arrayافتراضيًا لضمان التوافق مع JDBC. ويُجرى ذلك أيضًا لتوفير مزيد من المعلومات عن قيمة المصفوفة المُعادة. وهذا مفيد في استدلال النوع. - يوفّر
ArrayالتابعgetResultSet()لإرجاعjava.sql.ResultSetبالمحتوى نفسه الموجود في المصفوفة الأصلية. - لا ينبغي قراءة أنواع المجموعات باعتبارها
java.lang.Stringلأن هذه ليست طريقة صالحة لتمثيل البيانات (على سبيل المثال: لا تُوضَع قيم السلاسل النصية بين علامتَي اقتباس في المصفوفة). - يُعيَّن
MapإلىOTHERلأن القيمة لا يمكن قراءتها إلا باستخدام الطريقةgetObject(columnIndex, Class<T>).- لا يُعَدّ
Mapمن نوعjava.sql.Structلأنه لا يحتوي على أعمدة مُسمّاة.
- لا يُعَدّ
- يتم تمثيل
Tupleعلى شكلObject[]لأنه قد يحتوي على أنواع مختلفة، كما أن استخدامListغير صالح. - يمكن قراءة
TupleباعتبارهArrayباستخدام الطريقةgetObject(columnIndex, Array.class). في هذه الحالة، ستُعيدArray#baseTypeNameتعريف العمودTuple.
Array.getBaseTypeName() اسم نوع العنصر في ClickHouse؛ وتُعيد Array.getBaseType() رمز نوع JDBC.
يحتفظ JDBC V2 بتوقيعات النوع الكاملة (أنواع المُغلِّف، ومعاملات النوع) التي يحذفها V1.قواعد التعيين العامة للمصفوفات هي:ملاحظات حول القواعد أعلاه:
- يتم الاحتفاظ بالأنواع المغلِّفة (
Nullable,LowCardinality) فيgetBaseTypeName()، لكنgetBaseType()يُرجِع رمز JDBC للنوع الداخلي. - تُسطَّح المصفوفات المتداخلة في البيانات الوصفية: يُرجِع
getBaseTypeName()نوع العنصر الأعمق غير المصفوفي، وليس العنصر الفرعي المباشر. - تحتفظ الأنواع ذات المعلمات (
FixedString(N)، والتعريفات الكاملة لـEnum/Tuple) بمعلماتها فيgetBaseTypeName().
- في V2، تحتفظ
getBaseTypeName()بتوقيع النوع الكامل، بما في ذلك أنواع التغليف (NullableوLowCardinality) ومعلّمات النوع (FixedString(8)وتعريفاتEnumوTupleالكاملة). أما V1 فيُزيل هذه ويُرجع اسم النوع الأساسي فقط. - تستخدم مصفوفات
TupleالقيمةOTHER (1111)في V2 بدلًا منSTRUCT (2002)لأن Tuple في ClickHouse تتضمن حقولًا مسمّاة، وهو ما لا يدعمهjava.sql.Struct. - تستخدم مصفوفات
UUIDالقيمةOTHER (1111)في V2، بما يتوافق مع تعيينUUIDالقياسي. - تُعيَّن قيم
EnumإلىVARCHAR— إذ تُحدَّد عناصر enum باسمها النصي بغضّ النظر عن ترميزها الرقمي الأساسي.
java.sql.Connection#createArrayOf لإنشاء كائن java.sql.Array. صُمِّم هذا الكائن لتوحيد التعامل مع المصفوفات عبر قواعد البيانات المختلفة.
يُعدّ الاتصال ضروريًا لتمرير الإعدادات إلى أسلوب المصنع الخاص بـ Array.تقبل الطريقة وسيطَين:typeName- اسم نوع عناصر المصفوفة. على سبيل المثالArray(Int32)->"Int32".elements- عناصر المصفوفة نفسها. على سبيل المثال[[1, 2, 3], [4, 5, 6]]->new Integer[][] {{1, 2, 3}, {4, 5, 6}}.
Object[] أو java.sql.Struct (راجع كيفية كتابة Tuples أدناه).مثالResultSet#getArray(columnIndex) لقراءة كائن Array. يمكن استخدام هذا الكائن للوصول إلى مصفوفة بأي عمق تداخل.
يمكن استخدام الأسلوب Array#getResultSet() لقراءة عناصر المصفوفة بطريقة أكثر توحيدًا من خلال java.sql.ResultSet، وهو مفيد
عندما يكون النوع الدقيق لعناصر المصفوفة غير معروف.مثالcom.clickhouse.data.Tuple وينبغي كتابتها بوصفها هذا الكائن عبر استدعاء الأسلوب setObject(columnIndex, tuple).
يمكن استخدام كائن java.sql.Struct لكتابة tuples لتحقيق قدر أكبر من قابلية النقل.مثالgetObject(columnIndex) القيمة Object[]. يمكن قراءة Tuples بوصفها java.sql.Array باستخدام الدالة getObject(columnIndex, Array.class).مثالjava.collections.Map، إذ يستلزم هذا النوع أزواج مفتاح-قيمة (لا يدعم java.sql.Struct أزواج مفتاح-قيمة).مثالjava.collections.Map object باستخدام method getObject(columnIndex, Map.class).مثالjava.sql.Connection#createStruct لإنشاء كائن java.sql.Struct. صُمِّم هذا الكائن لتوحيد التعامل مع البنى المتداخلة عبر قواعد البيانات المختلفة.
يلزم توفر الاتصال لتمرير الإعدادات إلى دالة المصنع الخاصة بـ Struct.تقبل الدالة وسيطَين:typeName- اسم نوع العناصر المتداخلة. على سبيل المثالNested(Tuple(Int32, String))->"Nested(Tuple(Int32, String))".elements- العناصر المتداخلة نفسها. على سبيل المثال[1, 'test']->new Object[] {1, 'test'}.
ResultSet#getStruct(columnIndex, StructDescriptor) لقراءة كائن Nested. يمكن استخدام الكائن للوصول إلى العناصر المتداخلة بأي مستوى من مستويات التداخل.
يمكن استخدام الدالة Struct#getResultSet() لقراءة العناصر المتداخلة بأسلوب أكثر توحيدًا عبر java.sql.ResultSet، وهو مفيد
عندما يكون النوع الدقيق للعناصر المتداخلة غير معروف.مثالأنواع Nullable وLowCardinality
NullableوLowCardinalityنوعان خاصّان يغلّفان أنواعًا أخرى.- يؤثّر
Nullableعلى كيفية إرجاع أسماء الأنواع فيResultSetMetaData
- لا يُعد
UUIDنوعًا قياسيًا في JDBC. لكنه جزء من JDK. بشكل افتراضي، يُعادjava.util.UUIDمن الطريقةgetObject(). - يمكن قراءة
UUIDوكتابته على هيئةStringباستخدام الطريقةgetObject(columnIndex, String.class). - لا يُعد
IPv4وIPv6نوعين قياسيين في JDBC. لكنهما جزء من JDK. بشكل افتراضي، يُعادjava.net.Inet4Addressوjava.net.Inet6Addressمن الطريقةgetObject(). - يمكن قراءة
IPv4وIPv6وكتابتهما على هيئةStringباستخدام الطريقةgetObject(columnIndex, String.class).
Map<String, Object> افتراضيًا، حيث تكون مفاتيح JSON object هي keys وقيم JSON object هي values.
على سبيل المثال:jdbc_read_json_as_string=true إلى خصائص الاتصال.
يجعل هذا الـ driver يُعيد قيم JSON بوصفها String، ويمكن استخدامها لتحليل البيانات باستخدام أي مكتبة JSON.التعامل مع التواريخ والأوقات والمناطق الزمنية
يُرجى الاطلاع على دليل التاريخ والوقت الذي يشرح الأخطاء الشائعة ومنطق عمل الـ driver عند التعامل مع قيم التاريخ والوقت والـ timestamps.إنشاء اتصال
توفير بيانات الاعتماد والإعدادات
showLineNumbers
عبارة بسيطة
showLineNumbers
إدراج
showLineNumbers
HikariCP
showLineNumbers
مزيد من المعلومات
لمزيد من المعلومات، راجع مستودع GitHub الخاص بنا ووثائق Java Client.استكشاف الأخطاء وإصلاحها
التسجيل
يستخدم برنامج التشغيل slf4j للتسجيل، وسيستخدم أول تطبيق متاح علىclasspath.حل مشكلة انتهاء مهلة JDBC عند عمليات الإدراج الكبيرة
عند تنفيذ عمليات إدراج كبيرة في ClickHouse ذات أوقات تنفيذ طويلة، قد تواجه أخطاء انتهاء مهلة JDBC مثل:Mac OS
على نظام Mac OS، يمكن تعديل الإعدادات التالية لحل المشكلة:net.inet.tcp.keepidle: 60000net.inet.tcp.keepintvl: 45000net.inet.tcp.keepinit: 45000net.inet.tcp.keepcnt: 8net.inet.tcp.always_keepalive: 1
Linux
على Linux، قد لا تكفي الإعدادات المكافئة وحدها لحل المشكلة. ويعود ذلك إلى الاختلافات في طريقة تعامل Linux مع إعدادات keep-alive للمقبس، مما يستوجب اتخاذ خطوات إضافية. اتبع الخطوات التالية:- عدّل معلمات نواة Linux التالية في
/etc/sysctl.confأو في ملف تهيئة ذي صلة:
net.inet.tcp.keepidle: 60000net.inet.tcp.keepintvl: 45000net.inet.tcp.keepinit: 45000net.inet.tcp.keepcnt: 8net.inet.tcp.always_keepalive: 1net.ipv4.tcp_keepalive_intvl: 75net.ipv4.tcp_keepalive_probes: 9net.ipv4.tcp_keepalive_time: 60 (قد ترغب في خفض هذه القيمة من القيمة الافتراضية البالغة 300 ثانية)
- بعد تعديل معلمات النواة، طبِّق التغييرات عن طريق تشغيل الأمر التالي:
دليل الترحيل
التغييرات الرئيسية
- صُمم JDBC V2 ليكون أخف، وأزيلت منه بعض الميزات.
- البيانات المتدفقة غير مدعومة في JDBC V2 لأنها ليست جزءًا من مواصفة JDBC ولا من Java.
- يتطلب JDBC V2 إعدادًا صريحًا. لا توجد إعدادات افتراضية للتجاوز التلقائي.
- يجب تحديد البروتوكول في عنوان URL. لا يتم اكتشاف البروتوكول ضمنيًا بالاعتماد على أرقام المنافذ.
تغييرات الإعداد
يوجد نوعان فقط من أنواع enum:com.clickhouse.jdbc.DriverProperties- خصائص التهيئة الخاصة ببرنامج التشغيل.com.clickhouse.client.api.ClientConfigProperties- خصائص تهيئة العميل. التغييرات على تهيئة العميل موضحة في وثائق Java Client.
- يُحلَّل URL أولًا لاستخراج الخصائص. وتتجاوز هذه الخصائص جميع الخصائص الأخرى.
- لا تُمرَّر خصائص برنامج التشغيل إلى العميل.
- تُستخرَج نقاط النهاية (
hostوportوprotocol) من URL.
تغييرات أنواع البيانات
الأنواع الرقمية- أكبر اختلاف هو أن الأنواع غير الموقَّعة تُحوَّل إلى أنواع Java لتحسين قابلية النقل.
- تتم قراءة
FixedStringكما هي في كلا الإصدارين. على سبيل المثال، ستُقرأFixedString(10)للقيمة'John'على أنها'John\0\0\0\0\0\0\0\0\0'. - عند استخدام
PreparedStatement#setBytes، سيتم تحويله إلىunhex('<hex_string>')ثم تُقرأ القيمة كنوعString. - تُخزَّن السلاسل النصية بترميز UTF-8.
- يقتصر دعم
TimeوTime64في V2 على كونهما نوعين جديدين. - يُحوَّل
DateTimeوDateTime64إلىjava.sql.Timestampلتحقيق توافق أفضل مع JDBC.
الأنواع المتداخلة
- في V2، يُعيَّن
Arrayإلىjava.sql.Arrayافتراضيًا لضمان التوافق مع JDBC. ويُجرى ذلك أيضًا لتوفير معلومات إضافية عن قيمة المصفوفة المُعادة. وهذا مفيد في type inference. - في V2، يطبّق
ArrayالطريقةgetResultSet()لإرجاعjava.sql.ResultSetبالمحتوى نفسه الموجود في المصفوفة الأصلية. - يستخدم V1
STRUCTمعMap، لكنه يعيد دائمًا الكائنjava.util.Map. ويعالج V2 ذلك من خلال تعيينMapإلىJAVA_OBJECT. - يستخدم V1
STRUCTمعTuple، لكنه يعيد دائمًا الكائنList<Object>. ويُعيّن V2TupleإلىOTHERويعيدObject[]افتراضيًا. - يقدّم V2
com.clickhouse.data.Tuple#Tupleلكتابة قيم tuple. وهذا يسهّل تحديد ما إذا كانت القيمة tuple أم مصفوفة. - لا يمكن استخدام
PreparedStatement#setBytesوResultSet#getBytesمع أنواع المجموعات. فقد صُمّمت هاتان الطريقتان للعمل مع السلاسل الثنائية. - عادةً ما يُستخدم
java.sql.Arrayلكتابة أنواعArrayوقراءتها. ويوفّر JDBC driver دعمًا كاملًا لذلك. - في V2، يُعيَّن
NestedإلىArrayويعرضه كمصفوفة من tuples. - يوفّر V2 دعمًا جزئيًا لـ
java.sql.Structلأنه يشبه جدًا النوعArrayولا يدعم key-value pairs. ويمكن استخدامStructلكتابة قيمTuple.
أنواع Nullable وLowCardinality
NullableوLowCardinalityنوعان خاصّان يغلّفان أنواعًا أخرى.- لا تطرأ أي تغييرات على هذين النوعين في V2.
- يستخدم V1 النوع
VARCHARمعUUID، لكنه يعيد دائمًا الكائنjava.util.UUID. ويعالج V2 هذا الأمر من خلال تعيينUUIDإلىOTHER، ثم يعيد الكائنjava.util.UUID. - يستخدم V1 النوع
VARCHARمعIPv4وIPv6، لكنه يعيد دائمًا الكائنينjava.net.Inet4Addressوjava.net.Inet6Address. ويعالج V2 هذا الأمر من خلال تعيينIPv4وIPv6إلىOTHER، ثم يعيد الكائنينjava.net.Inet4Addressوjava.net.Inet6Address. DynamicوVariantنوعان جديدان في V2. ولا يدعمهما V1.- يعتمد
JSONعلى النوعDynamic. لذلك فهو مدعوم فقط في V2. - يمكن قراءة قيم
IPv4وIPv6على هيئةbyte[]باستخدام الدالةgetBytes(columnIndex). ومع ذلك، يُوصى باستخدام الفئات المخصّصة لهذه الأنواع. - لا يدعم V2 قراءة عنوان IP على أنه من القيم العددية، لأن التحويل مُنفَّذ بصورة أفضل في فئات
InetAddress.
تغييرات البيانات الوصفية لقاعدة البيانات
- يستخدم V2 المصطلح
Schemaفقط لتسمية قواعد البيانات. أما المصطلحCatalogفمحجوز للاستخدام المستقبلي. - يعيد V2 القيمة
falseلكل منDatabaseMetaData.supportsTransactions()وDatabaseMetaData.supportsSavepoints(). سيتغير ذلك في الإصدارات القادمة. - في
DatabaseMetaData.getTypeInfo()، يُرجِع العمودانLITERAL_PREFIXوLITERAL_SUFFIXالآن القيمةnullلأنواع البيانات التي لا يُتوقع أن تحتوي على بادئات أو لاحقات (مثل الأنواع الرقمية). في V1، كانت هذه الأعمدة تُرجِع قيماً غيرnullلهذه الأنواع. ينبغي استخدام هذه الأعمدة عند إنشاء استعلامات SQL لوضع القيم الحرفية بين علامتي اقتباس بشكل صحيح وفقاً لنوع بياناتها.