Ralat & Penyelesaian Pasukan Lucee MY

Ralat pangkalan data dan mel dalam Lucee: enam punca yang senyap

Enam ralat Lucee yang senyap: datasource type lawan driver, cfmail dalam servis, LAST_INSERT_ID pulang 0, UTF-8 rosak, JDBC OSGi dan migrasi berganda.

0
Kandungan

Ralat pangkalan data dan mel dalam Lucee: enam punca yang senyap

Ralat pangkalan data dan mel dalam Lucee jarang memberi mesej yang jelas. Ada yang pulang sifar baris, ada yang melaporkan berjaya sedangkan tiada apa berlaku, dan ada yang mematikan seluruh laman tanpa menyebut fail yang salah. Enam di bawah ini ialah yang paling kerap, dan setiap satu mempunyai punca yang tetap.

Kenapa Lucee kata datasource tidak wujud walaupun ia sudah didaftarkan?

Mesej:

Datasource [inventori] doesn't exist

Puncanya hampir selalu satu perkataan dalam pendaftaran datasource. Dalam tetapan Lucee, medan itu bernama type, bukan driver.

this.datasources["inventori"] = {
    driver: "mysql",
    host: "127.0.0.1",
    database: "inventori"
};

Kod di atas kelihatan betul kerana driver memang nama lazim dalam bahasa lain, tetapi Lucee mengabaikannya dan mendaftarkan datasource tanpa jenis yang sah. Hasilnya, datasource itu tidak wujud pada masa cfquery.

Pembetulan:

this.datasources["inventori"] = {
    type: "mysql",
    host: "127.0.0.1",
    port: 3306,
    database: "inventori",
    username: "aplikasi",
    password: "rahsia"
};

Selepas menukar tetapan datasource dalam Application.cfc, aplikasi mesti dimulakan semula. Menyimpan fail itu sahaja tidak mendaftarkan semula datasource.

Kalau datasource didaftarkan melalui Lucee Admin dan bukan dalam kod, semak juga nama persekitaran: satu datasource dalam kumpulan pentadbir tidak semestinya tersedia untuk aplikasi web tertentu. Artikel khusus datasource membincangkan perkara ini lebih lanjut.

Kenapa cfmail tidak menghantar apa-apa dalam servis tetapi berfungsi dalam handler?

Ini antara pepijat paling menipu kerana cfmail tidak membaling ralat. Ia melaporkan berjaya, dan mesej tidak pernah sampai.

Gejalanya: satu servis dalam app/services/ memanggil cfmail, tiada ralat dalam log aplikasi, tetapi log Postfix tidak menunjukkan sebarang sambungan.

Puncanya ialah cfmail di dalam komponen perkhidmatan tidak dihantar dalam sesetengah versi Lucee, termasuk 7.1.0.204. Tag yang sama, dengan argumen yang sama, di dalam pengendali berfungsi dan direkodkan oleh Postfix.

Pembetulan: pindahkan penghantaran ke pengendali, dan biarkan servis hanya menyediakan teks.

<!--- dalam handler --->
<cfoutput>
<cfmail to="#penerima#" from="contact@lucee.my" subject="#subjek#" type="html">
    #teksHtml#
</cfmail>
</cfoutput>

Bukti penghantaran bukan nilai pulangan cfmail. Yang membuktikan ialah baris postfix/submission/smtpd dengan sasl_username dalam log Postfix, dan mesej yang muncul dalam peti mel penerima.

Kenapa LAST_INSERT_ID() pulang 0 selepas INSERT?

Mesej:

0

Kes ini berlaku apabila INSERT dan SELECT LAST_INSERT_ID() dijalankan dalam dua panggilan mysql -e yang berasingan.

mysql -e "INSERT INTO posts (title) VALUES ('Ujian')"
mysql -N -e "SELECT LAST_INSERT_ID()"

Setiap panggilan mysql -e membuka sambungan baharu, dan LAST_INSERT_ID() hanya bermakna dalam sambungan yang sama. Sambungan kedua tidak mempunyai INSERT, jadi ia memulangkan 0.

Pembetulan: letak kedua-dua kenyataan dalam satu panggilan.

mysql -N -e "INSERT INTO posts (title) VALUES ('Ujian'); SELECT LAST_INSERT_ID();"

Untuk skrip yang memerlukan id itu di tempat lain, lebih selamat jana id sendiri atau gunakan kunci semula jadi seperti slug, kemudian SELECT id FROM posts WHERE slug = '...'. Cara itu tidak bergantung pada keadaan sambungan.

Kenapa teks Melayu rosak selepas dipindahkan melalui MySQL?

Gejala: teks yang betul dalam pangkalan data muncul sebagai é atau ? selepas dipindahkan melalui skrip.

Puncanya ada dua lapisan. Pertama, sambungan mysql tanpa --default-character-set=utf8mb4 boleh menukar aksara semasa menghantar hasil. Kedua, mod kelompok menukar baris baharu dan tab menjadi huruf \n dan \t, yang merosakkan teks berbilang baris seperti markdown.

mysql -N -e "SELECT body_md FROM posts WHERE id = 166" > /tmp/body.md

Pembetulan: baca ke fail dengan tetapan yang betul.

mysql --default-character-set=utf8mb4 -N --raw -e "SELECT body_md FROM posts WHERE id = 166" > /tmp/body.md

--raw menyelesaikan dua masalah sekali: ia mengekalkan UTF-8 dan menghentikan mod kelompok daripada melarikan aksara kawalan. Selepas itu, hantar fail itu semula tanpa melalui pemboleh ubah teks dalam Python, kerana satu bait seperti 0xb7 boleh menyebabkan UnicodeDecodeError yang menghentikan skrip di tengah jalan.

Kenapa DriverManager gagal dalam Lucee 7?

Mesej:

No suitable driver found

Kod JDBC biasa tidak berfungsi dalam Lucee 7 kerana pemacu hidup di dalam sempadan OSGi.

DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/db", props)

Class.forName("com.mysql.cj.jdbc.Driver") juga gagal dengan not found by lucee.core, walaupun JAR itu ada.

Pembetulan: instantiate pemacu itu sendiri, kemudian sambung pada objek itu.

<cfset pemacu = createObject("java", "com.mysql.cj.jdbc.Driver").init()>
<cfset sambungan = pemacu.connect("jdbc:mysql://127.0.0.1:3306/db", sifat)>

Amalan yang baik: jangan namakan pemboleh ubah itu url, kerana url ialah skop terbina dan nilainya akan bertukar menjadi struct. Guna jdbcUrl atau alamatSambungan.

Kenapa laman mati selepas saya jalankan fail migrasi dengan tangan?

Gejala: migrasi berjaya, kemudian setiap halaman membalas 500 selepas mula semula berikutnya.

Puncanya, fail migrasi dijalankan terus ke MySQL tanpa menulis baris dalam schema_version. Pada mula semula berikutnya, aplikasi menyangka migrasi itu belum dijalankan, menjalankannya sekali lagi, dan ALTER TABLE ... ADD COLUMN gagal dengan Duplicate column name. Pengecualian itu membatalkan app start.

Pembetulan: jangan jalankan fail SQL dengan tangan. Biarkan aplikasi menjalankan migrasi semasa mula semula, kemudian sahkan baris dalam schema_version dan lajur baharu.

Kalau sudah terlanjur, tulis baris itu secara manual sebelum memulakan semula.

INSERT IGNORE INTO schema_version (version, name, applied_at)
VALUES (7, '007_contoh.sql', UTC_TIMESTAMP());

Selepas itu, mula semula dan sahkan laman kembali 200. Urutan yang selamat bermula dengan membiarkan aplikasi menjalankan migrasi sendiri, kemudian mengesahkan hasilnya.

Corak di sebalik enam ralat ini

Lima daripada enam ralat ini tidak memberi mesej yang menunjukkan punca sebenar. Datasource yang salah nama medan melaporkan "tidak wujud", cfmail melaporkan berjaya, LAST_INSERT_ID melaporkan 0, dan migrasi berganda hanya kelihatan pada permulaan seterusnya.

Kerana itu, apabila kerja melibatkan pangkalan data atau mel, sahkan kesan pada sistem luar: baris dalam jadual, baris dalam log Postfix, dan kod HTTP selepas mula semula. Jangan percaya nilai pulangan tag.

Ralat yang menghalang halaman daripada berjalan langsung mempunyai punca yang berbeza, dan ia biasanya kelihatan sebagai mesej kompilasi atau sebagai halaman 500 tanpa butiran.

Cara mengesahkan sambungan pangkalan data dengan cepat

Sebelum menyalahkan kod, buktikan tiga perkara: datasource wujud, pertanyaan berjalan, dan data yang dibaca betul.

<cfdump var="#application.datasourceExists('inventori')#" label="Datasource">

Kalau nilai itu true, pendaftaran bukan masalahnya. Kemudian jalankan pertanyaan paling kecil yang mungkin.

<cfquery name="ujian" datasource="inventori">
    SELECT 1 AS satu
</cfquery>
<cfdump var="#ujian#" label="Ujian">

Kalau ini berjaya, kod anda yang salah. Kalau ia gagal dengan Communications link failure, pelayan MySQL belum sedia atau kredensial salah.

Langkah ketiga ialah membandingkan data dengan jangkaan.

<cfquery name="kira" datasource="inventori">
    SELECT COUNT(*) AS jumlah FROM produk
</cfquery>
<cfdump var="#kira.jumlah#" label="Bilangan produk">

Angka yang tidak sepadan selalunya bermakna pertanyaan anda menapis lebih daripada yang disangka, bukan bermakna sambungan rosak.

Untuk mel, gantikan tiga langkah itu dengan satu: hantar satu mesej ke peti anda sendiri, kemudian baca log Postfix. Kalau tiada baris smtpd, cfmail tidak pernah bercakap dengan pelayan mel, dan itu bermakna kod itu tidak menghantar walaupun ia melaporkan berjaya.

Soalan Lazim

Adakah type: "mysql" berfungsi untuk MariaDB? Ya. MariaDB menggunakan pemacu MySQL yang sama dalam Lucee, dan nama jenis yang diterima ialah mysql.

Boleh saya simpan kata laluan datasource dalam Application.cfc? Boleh untuk pembangunan, tetapi di pelayan hidup simpan dalam fail persekitaran yang tidak masuk git, kemudian baca semasa app start.

Kenapa cfmail berfungsi di satu halaman tetapi tidak di halaman lain? Kerana satu halaman memanggil cfmail dari handler, satu lagi dari servis. Dalam versi Lucee yang terjejas, hanya laluan handler yang benar-benar menghantar.

Perlukah setiap migrasi menulis schema_version? Ya. Aplikasi menggunakan jadual itu untuk memutuskan apa yang perlu dijalankan. Fail tanpa baris akan dijalankan semula.

Bagaimana mengesan ralat seperti ini sebelum pengguna melihatnya? Tambah satu probe kesihatan yang membaca satu baris dari pangkalan data, menghantar satu e-mel ujian ke peti sendiri, dan menyemak bilangan rekod. Tiga pemeriksaan itu menangkap kebanyakan ralat senyap dalam beberapa saat.

Sumber

0 komen

0 komen

Log masuk untuk menjawab atau memberi komen.

Log masuk