Clojure如何在数据库中插入blob?

时间:2010-09-03 00:34:31

标签: database clojure

如何使用clojure.contrib.sql在数据库中插入blob?

我已尝试从文件中读取以下内容,但我得到了这个例外:

的SQLException:  消息:列类型无效  SQLState:99999  错误代码:17004 java.lang.Exception:事务回滚:列类型无效(repl-1:125)

(clojure.contrib.sql/with-connection
   db
   (clojure.contrib.sql/transaction
    (clojure.contrib.sql/insert-values :test_blob [:blob_id :a_blob] [3   (FileInputStream. "c:/somefile.xls")]) ))

感谢。

4 个答案:

答案 0 :(得分:2)

我能够通过将FileInputStream转换为ByteArray来解决这个问题。

(clojure.contrib.sql/with-connection 
   db 
   (clojure.contrib.sql/transaction 
    (clojure.contrib.sql/insert-values :test_blob [:blob_id :a_blob] [3   (to-byte-array(FileInputStream. "c:/somefile.xls"))]) )) 

答案 1 :(得分:2)

理论上,您可以使用任何clojure.contrib.sql / insert- *方法插入blob,将blob作为字节数组,java.sql.Blob或java.io.InputStream对象传递。在实践中,它取决于驾驶员。

对于许多JDBC实现,所有上述工作都按预期工作,但如果你使用Clojars的sqlitejdbc 0.5.6,你会发现你的blob通过toString()强制转换为字符串。所有clojure.contrib.sql / insert- *命令都是通过clojure.contrib.sql / do-prepared发出的,它在java.sql.PreparedStatement上调用setObject()。 sqlitejdbc实现不处理任何blob数据类型的setObject(),但默认情况下将它们强制转换为字符串。这是一个解决方法,使您可以在SQLite中存储blob:

  (use '[clojure.contrib.io :only (input-stream to-byte-array)])
  (require '[clojure.contrib.sql :as sql])

  (defn my-do-prepared
   "Executes an (optionally parameterized) SQL prepared statement on the
   open database connection. Each param-group is a seq of values for all of
   the parameters. This is a modified version of clojure.contrib.sql/do-prepared
   with special handling of byte arrays."
   [sql & param-groups]
   (with-open [stmt (.prepareStatement (sql/connection) sql)]
     (doseq [param-group param-groups]
       (doseq [[index value] (map vector (iterate inc 1) param-group)]
         (if (= (class value) (class (to-byte-array "")))
           (.setBytes stmt index value)
           (.setObject stmt index value)))
       (.addBatch stmt))
     (sql/transaction
      (seq (.executeBatch stmt)))))

 (defn my-load-blob [filename]
   (let [blob (to-byte-array (input-stream filename))]
     (sql/with-connection db
           (my-do-prepared "insert into mytable (blob_column) values (?)" [blob]))))

答案 2 :(得分:0)

我相信它与您插入任何其他值的方式相同:使用insert-recordsinsert-rowsinsert-values之一。 E.g:

(insert-values :mytable [:id :blobcolumn] [42 blob])

更多示例:http://github.com/richhickey/clojure-contrib/blob/master/src/test/clojure/clojure/contrib/test_sql.clj

答案 3 :(得分:0)

对此线程的最新回复还包括读取数据的代码:

(ns com.my-items.polypheme.db.demo
  (:require
   [clojure.java.io :as io]
   [clojure.java.jdbc :as sql]))

(def db {:dbtype "postgresql"
         :dbname "my_db_name"
         :host "my_server"
         :user "user",
         :password "user"})

(defn file->bytes [file]
  (with-open [xin (io/input-stream file)
              xout (java.io.ByteArrayOutputStream.)]
    (io/copy xin xout)
    (.toByteArray xout)))

(defn insert-image [db-config file]
  (let [bytes (file->bytes file)]
    (sql/with-db-transaction [conn db-config]
      (sql/insert! conn :image {:name (.getName file) :data bytes}))))

(insert-image db (io/file "resources" "my_nice_picture.JPG"))

;;read data
(defn read-image [db-config id]
  (-> (sql/get-by-id db-config :image id)
      :data
      (#(new java.io.ByteArrayInputStream %))))