Panduan Pasukan Lucee MY

queryExecute dalam CFML: parameter, cache dan metadata

Panduan queryExecute dalam CFML: parameter bernama dan berkedudukan, struct options dengan cfsqltype, null dan list, metadata hasil, transaksi dan caching.

queryExecute dalam CFML: parameter, cache dan metadata
0
Kandungan

queryExecute dalam CFML: parameter, cache dan metadata

queryExecute() ialah fungsi CFML yang menjalankan satu arahan SQL dan memulangkan objek query. Ia padanan moden bagi tag cfquery, tetapi ditulis sebagai fungsi cfscript, jadi ia boleh dipanggil di dalam fungsi, komponen dan gelung tanpa keluar dari blok skrip. Artikel ini merangkumi parameter, metadata hasil, transaksi dan caching, bersama perbandingan dengan cfquery.

queryExecute menggantikan cfquery

Gaya tag memerlukan anda keluar dari cfscript setiap kali mahu bertanya kepada pangkalan data, dan hasilnya disimpan dalam pemboleh ubah bernama. queryExecute() memulangkan query sebagai nilai, jadi anda boleh menyimpannya, memulangkannya dari fungsi, atau menghantarnya sebagai argumen. Contoh paling ringkas:

<cfscript>
q = queryExecute(
    sql = "SELECT id, nama, emel FROM ahli WHERE aktif = :aktif ORDER BY id",
    params = { aktif = { value = 1, cfsqltype = "cf_sql_integer" } },
    options = { datasource = "mydb" }
);
writeOutput(q.recordCount);
</cfscript>

Dari segi prestasi, kedua-duanya menggunakan enjin pelaksanaan yang sama, jadi perbezaan kelajuan boleh diabaikan. Kelebihan queryExecute() ialah kemudahan penulisan, bukan kelajuan. Nama datasource seperti mydb bergantung pada tetapan anda; baca panduan konfigurasi datasource untuk mendaftarkannya.

Parameter bernama dan berkedudukan

Parameter bernama menggunakan titik bertindih di hadapan nama, dan params memadankan nama dengan struktur nilai:

<cfscript>
q = queryExecute(
    sql = "SELECT id, nama FROM produk WHERE id IN (:id)",
    params = { id = { value = "1,2", cfsqltype = "cf_sql_integer", list = true } },
    options = { datasource = "mydb" }
);
</cfscript>

Parameter berkedudukan menggunakan tanda soal dan tatasusunan mengikut susunan:

<cfscript>
q = queryExecute(
    sql = "SELECT id, nama FROM ahli WHERE id IN (?, ?)",
    params = [
        { value = 1, cfsqltype = "cf_sql_integer" },
        { value = 2, cfsqltype = "cf_sql_integer" }
    ],
    options = { datasource = "mydb" }
);
</cfscript>

Kedua-dua bentuk menghasilkan pertanyaan berparameter yang sama. Gunakan bentuk bernama apabila pertanyaan panjang supaya kod mendokumenkan dirinya sendiri, dan bentuk berkedudukan apabila senarai pendek.

Struct options dan kekunci parameter

Argumen ketiga ialah struktur options; kekunci yang paling kerap ialah datasource. Dalam params, setiap parameter membawa kunci tambahan selain value dan cfsqltype. null bernilai true menghantar SQL NULL dan mengabaikan value, maxlength menambah semakan panjang, dan list bernilai true memperluas nilai untuk operator IN:

<cfscript>
transaction {
    queryExecute(
        sql = "INSERT INTO pelanggan (id, nama, emel, telefon) VALUES (88, 'Uji', :emel, :tel)",
        params = {
            emel = { null = true, cfsqltype = "cf_sql_varchar" },
            tel = { value = "0130000000", cfsqltype = "cf_sql_varchar", maxlength = 20 }
        },
        options = { datasource = "mydb" }
    );
    transactionRollback();
}
</cfscript>

Blok ini dibungkus transaksi dan digulingkan semula supaya selamat dijalankan berulang kali.

Mengelak suntikan SQL dengan parameter

Suntikan SQL berlaku apabila nilai pengguna dicantum ke dalam rentetan SQL. queryExecute() tidak menjadikan pertanyaan selamat secara automatik; ia selamat hanya apabila setiap nilai dinamik melalui params. Pertanyaan yang tidak selamat:

<cfscript>
nama = "' OR '1'='1";
q = queryExecute(
    "SELECT * FROM ahli WHERE nama = '" & nama & "'",
    [],
    { datasource = "mydb" }
);
writeOutput(q.recordCount);   // 3, semua baris terbocor
</cfscript>

Versi selamat mengikat nilai sebagai parameter, dan input yang sama kini memulangkan sifar padanan:

<cfscript>
nama = "' OR '1'='1";
q = queryExecute(
    sql = "SELECT * FROM ahli WHERE nama = :nama",
    params = { nama = { value = nama, cfsqltype = "cf_sql_varchar" } },
    options = { datasource = "mydb" }
);
writeOutput(q.recordCount);   // 0, tiada padanan
</cfscript>

Peraturannya tidak berkompromi: apa-apa nilai dari pengguna mesti melalui params. Penjelasan penuh bersama jenis serangan yang dicegah ada dalam panduan mencegah suntikan SQL.

Membaca metadata hasil

Objek query membawa maklumat hasilnya sendiri tanpa pertanyaan kedua:

<cfscript>
q = queryExecute("SELECT id, nama FROM ahli WHERE id = 1", [], { datasource = "mydb" });
writeOutput(q.recordCount);        // bilangan baris, 1
writeOutput(q.columnList);         // "ID,NAMA"
meta = getMetaData(q);             // tatasusunan metadata lajur
writeOutput(meta[1].name);         // "ID"
writeOutput(meta[1].typeName);     // "INTEGER"
</cfscript>

recordCount memberi bilangan baris dan columnList senarai nama lajur dipisahkan koma. getMetaData() memulangkan tatasusunan struktur dengan kekunci name, typeName dan isCaseSensitive. Tiada sifat columnMeta pada objek query, jadi gunakan getMetaData().

Hasil kosong dan NULL

Pertanyaan tanpa padanan tidak melempar ralat; ia memulangkan recordCount sifar, dan anda mesti menyemaknya sebelum membaca nilai:

<cfscript>
q = queryExecute("SELECT id, nama FROM ahli WHERE id = 9999", [], { datasource = "mydb" });
if (q.recordCount == 0) {
    writeOutput("Tiada rekod dijumpai");
}
</cfscript>

NULL pula bermaksud tiada nilai, berbeza daripada rentetan kosong. Untuk menulis NULL, gunakan null = true dalam parameter. Untuk menapis lajur NULL, gunakan IS NULL dan bukan = NULL, kerana = NULL tidak pernah benar dalam kebanyakan pangkalan data.

queryExecute dalam transaksi

Transaksi mengumpulkan beberapa pertanyaan menjadi satu unit yang sama ada berjaya atau gagal sepenuhnya. Dalam cfscript, queryExecute() berfungsi dalam blok transaction, dan anda boleh membatalkan semuanya dengan transactionRollback():

<cfscript>
transaction {
    queryExecute(
        "UPDATE ahli SET aktif = 0 WHERE id = :id",
        { id = { value = 1, cfsqltype = "cf_sql_integer" } },
        { datasource = "mydb" }
    );
    transactionRollback();
}
</cfscript>

Jika pertanyaan dalam blok melempar pengecualian, Lucee menggulingkan transaksi secara automatik. Butiran komit, rollback dan savepoint ada dalam panduan cftransaction.

Caching hasil dengan cachedWithin

Apabila pertanyaan sama dijalankan berulang kali dan datanya jarang berubah, anda boleh menyimpan hasilnya supaya panggilan berikutnya tidak menyentuh pangkalan data:

<cfscript>
q = queryExecute(
    sql = "SELECT id, nama FROM ahli WHERE id = 1",
    params = [],
    options = {
        datasource = "mydb",
        cachedwithin = createTimeSpan(0, 0, 0, 60),
        result = "hasil"
    }
);
writeOutput(hasil.cached);   // false kali pertama, true selepas itu
</cfscript>

cachedwithin menerima tempoh masa dari createTimeSpan(), dan cachedafter menerima tarikh. Untuk cache dikira padanan, SQL, parameter, datasource dan nama query mesti sama. Struktur result membawa bendera cached dan executionTime dalam mikrosaat untuk mengesahkan cache berfungsi. Atribut lama seperti cache boolean, cacheId dan cacheName sudah lapuk atau tidak dilaksanakan dalam Lucee semasa; gunakan cachedwithin dan cachedafter.

Bila caching berbahaya

Caching menyimpan jawapan lama, dan jawapan lama menjadi salah sebaik sahaja data berubah. Untuk jadual yang kerap dikemas kini seperti stok atau status pesanan, caching berisiko memaparkan maklumat lapuk, lebih buruk daripada pertanyaan perlahan. Gunakan cachedwithin hanya untuk data yang berubah perlahan, seperti senarai negeri atau kategori produk, dan tetapkan tempoh pendek berbanding kekerapan perubahan. Jika anda menyambung kepada MySQL, semak panduan sambungan MySQL dengan Lucee sebelum memikirkan cache.

Jadual cfsqltype yang biasa digunakan

Menetapkan cfsqltype yang betul membantu Lucee menukar jenis dengan tepat dan menolak nilai yang salah jenis sebelum sampai ke pangkalan. Nilai boleh ditulis dengan atau tanpa awalan CF_SQL_.

Jenis dataKegunaanContoh nilai
varcharRentetan teks, jenis lalai"thalhah"
integerNombor bulat42
bigintInteger besar9007199254740993
decimal / double / moneyNombor perpuluhan atau kewangan19.90
boolean / bitNilai benar atau salahtrue
date / time / timestampTarikh dan masacreateDate(2026,10,6)
binary / blobData binarifileReadAsBinary(f)

Jadual perbandingan queryExecute lawan cfquery

AspekqueryExecutecfquery
BentukFungsi cfscriptTag CFML
HasilNilai dipulangkanPemboleh ubah bernama
Skop hasilAnda tentukan tempat simpanvariables atau local
ParameterStruktur params atau tatasusunanTag cfqueryparam
Dalam blok skripBoleh terusPerlu keluar dari skrip
PrestasiEnjin sama, tanpa overhed tagEnjin sama

Kedua-duanya bukan musuh. Kod gaya tag kekal dengan cfquery, kod cfscript memilih queryExecute(). Yang penting ialah konsisten dalam satu fail.

Soalan Lazim (FAQ)

Adakah queryExecute lebih pantas daripada cfquery?

Tidak secara bermakna. Kedua-duanya menggunakan enjin yang sama, jadi perbezaan kelajuan boleh diabaikan. Kelebihan queryExecute() ialah kemudahan penulisan dalam cfscript.

Bagaimana saya menghantar senarai nilai untuk operator IN?

Gunakan list = true pada parameter dengan nilai senarai atau tatasusunan, dan Lucee menaip setiap elemen mengikut cfsqltype.

Apakah cara betul untuk menulis NULL ke pangkalan data?

Gunakan null = true dalam struktur parameter. Lucee menghantar SQL NULL dan mengabaikan kekunci value.

Bolehkah queryExecute menjadikan pertanyaan saya selamat daripada suntikan SQL?

Tidak secara automatik. Ia selamat hanya apabila setiap nilai dinamik dihantar melalui params. Cantuman nilai ke dalam rentetan masih terdedah.

Atribut cache mana yang sepatutnya saya guna?

Gunakan cachedwithin dengan createTimeSpan(), atau cachedafter dengan tarikh. Atribut cache boolean, cacheId dan cacheName sudah lapuk atau tidak dilaksanakan.

Sumber

Senarai semak

  • Gunakan queryExecute() untuk cfscript dan cfquery untuk gaya tag, konsisten dalam satu fail.
  • Hantar setiap nilai dinamik melalui params, tidak pernah dicantum ke dalam rentetan SQL.
  • Nyatakan cfsqltype yang sepadan dengan jenis lajur, dan gunakan list, null serta maxlength mengikut keperluan.
  • Semak recordCount sebelum membaca nilai, dan gunakan getMetaData() untuk metadata lajur.
  • Gunakan cachedwithin hanya untuk data yang jarang berubah, dan sahkan dengan bendera cached pada struct result.

Log masuk untuk menyimpan kemajuan bacaan anda.

0 komen

0 komen

Log masuk untuk menjawab atau memberi komen.

Log masuk