本文主要是介绍Spring源代码分析(13)---BLOB和CLOB操作(不是大就了不起),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
我们在项目中,经常碰到图片存储,文章存储的问题,在这类问题的解决方案中,我们经常是采用把这类大数据对象保存在文件系统中,但是这又带来了一系列问题,图片存储在文件系统中,很不安全,很多情况都是能够被人所copy,破坏等等,那么,我们可以选择将其保存在数据库中,主流数据库都已经基本实现了 Blob,Clob等数据字段类型,但是,因为JDBC没有一个Blob,Clob的具体类型实现,每种数据库对这种类型存储机制都不相同,因此,大大的降低了我们的系统在数据库的迁移性,那么这一些Spring来帮助我们解决这个该死的强耦合,大,并不是就了不起!首先:
applicationContext.xml:
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
- <bean id="dataSource"
- class="org.apache.commons.dbcp.BasicDataSource">
- <property name="driverClassName"
- value="com.mysql.jdbc.Driver">
- </property>
- <property name="url" value="jdbc:mysql://127.0.0.1:3306/test"></property>
- <property name="username" value="root"></property>
- </bean>
- <!-- 用户获取Oracle源连接 -->
- <bean id="nativeJdbcExtrector" name="nativeJdbcExtrector"
- class="org.springframework.jdbc.support.nativejdbc.C3P0NativeJdbcExtractor"
- abstract="false" lazy-init="default" autowire="default"
- dependency-check="default">
- </bean>
- <!-- Oracle大对象处理器 -->
- <bean id="oracleLobHandler" name="oracleLobHandler"
- class="org.springframework.jdbc.support.lob.OracleLobHandler"
- abstract="false" lazy-init="default" autowire="default"
- dependency-check="default">
- <property name="nativeJdbcExtractor">
- <ref bean="nativeJdbcExtractor"></ref>
- </property>
- </bean>
- <bean id="defaultLobhandler" name="defaultLobhandler"
- class="org.springframework.jdbc.support.lob.DefaultLobHandler"
- abstract="false" lazy-init="default" autowire="default"
- dependency-check="default">
- </bean>
- <bean id="lobDao" name="lobDao" class="LobDaoSupport"
- abstract="false" lazy-init="default" autowire="default"
- dependency-check="default">
- <property name="lobHandler">
- <ref bean="oracleLobHandler"></ref>
- </property>
- </bean>
- </beans>
代码:
- package org.syna.demo;
- import org.springframework.jdbc.support.lob.LobHandler;
- public interface Lober {
- /**
- * 设置大对象处理器
- * @param handler
- */
- public void setLobHandler(LobHandler handler);
- }
- package org.syna.demo;
- import java.util.List;
- public interface ImageReader {
- /**
- * 获取存储在数据库中的图片的描述,其类型为Clob
- * @param imageID
- * @return
- */
- public List getImageDescription();
- /**
- * 获取存储在数据库中的图片的输入流,其类型类Blob
- * @param imageID
- * @return
- */
- public List getImage();
- }
- package org.syna.demo;
- import java.sql.ResultSet;
- import java.sql.SQLException;
- import java.util.List;
- import org.springframework.jdbc.core.RowMapper;
- import org.springframework.jdbc.core.support.JdbcDaoSupport;
- import org.springframework.jdbc.support.lob.LobHandler;
- public class LobDaoSupport extends JdbcDaoSupport implements ImageReader, Lober {
- private LobHandler lobHandler;
- public void setLobHandler(LobHandler handler) {
- this.lobHandler = handler;
- }
- public List getImage() {
- return this.getJdbcTemplate().query("select Iamge from Images ",
- new RowMapper() {
- public Object mapRow(ResultSet rs, int rowNum)
- throws SQLException {
- return lobHandler.getBlobAsBytes(rs, 1);
- }
- });
- }
- public List getImageDescription() {
- return this.getJdbcTemplate().query("select descripton from images",
- new RowMapper() {
- public Object mapRow(ResultSet rs, int rowNum)
- throws SQLException {
- String description = lobHandler.getClobAsString(rs, 1);
- return description;
- }
- });
- }
- private LobHandler handler;
- }
- public interface LobHandler {
- //将Blob对象转换为byte数组;
- byte[] getBlobAsBytes(ResultSet rs, String columnName) throws SQLException;
- byte[] getBlobAsBytes(ResultSet rs, int columnIndex) throws SQLException;
- //将Blob对象转换为流
- InputStream getBlobAsBinaryStream(ResultSet rs, String columnName) throws SQLException;
- InputStream getBlobAsBinaryStream(ResultSet rs, int columnIndex) throws SQLException;
- //将Clob转换为字符串
- String getClobAsString(ResultSet rs, String columnName) throws SQLException;
- String getClobAsString(ResultSet rs, int columnIndex) throws SQLException;
- //将Clob转为流
- InputStream getClobAsAsciiStream(ResultSet rs, String columnName) throws SQLException;
- InputStream getClobAsAsciiStream(ResultSet rs, int columnIndex) throws SQLException;
- Reader getClobAsCharacterStream(ResultSet rs, String columnName) throws SQLException;
- /
- Reader getClobAsCharacterStream(ResultSet rs, int columnIndex) throws SQLException;
- //得到一个Lob对象的工厂,他能够生产出Blob和Clob,
- //等会会进行详细分析;
- LobCreator getLobCreator();
- }
- public class OracleLobHandler extends AbstractLobHandler {
- //Oracle大对象类的具体实现,经常我们就是在这里与数据库造成耦 //合,因为Mysql也有自己的实现;
- private static final String BLOB_CLASS_NAME = "oracle.sql.BLOB";
- private static final String CLOB_CLASS_NAME = "oracle.sql.CLOB";
- private static final String DURATION_SESSION_FIELD_NAME = "DURATION_SESSION";
- private static final String MODE_READWRITE_FIELD_NAME = "MODE_READWRITE";
- protected final Log logger = LogFactory.getLog(getClass());
- //一个JDBC本地抽取器;对代理连接等等作出抽取;
- private NativeJdbcExtractor nativeJdbcExtractor;
- private Boolean cache = Boolean.TRUE;
- private Class blobClass;
- private Class clobClass;
- private final Map durationSessionConstants = new HashMap(2);
- private final Map modeReadWriteConstants = new HashMap(2);
- //在这里我们可以设置成为Oracle的抽取器;
- public void setNativeJdbcExtractor(NativeJdbcExtractor nativeJdbcExtractor) {
- this.nativeJdbcExtractor = nativeJdbcExtractor;
- }
- public void setCache(boolean cache) {
- this.cache = new Boolean(cache);
- }
- //初始化驱动类的大对象;
- protected synchronized void initOracleDriverClasses(Connection con) {
- if (this.blobClass == null) {
- try {
- // Initialize oracle.sql.BLOB class
- this.blobClass = con.getClass().getClassLoader().loadClass(BLOB_CLASS_NAME);
- this.durationSessionConstants.put(
- this.blobClass, new Integer(this.blobClass.getField(DURATION_SESSION_FIELD_NAME).getInt(null)));
- this.modeReadWriteConstants.put(
- this.blobClass, new Integer(this.blobClass.getField(MODE_READWRITE_FIELD_NAME).getInt(null)));
- // Initialize oracle.sql.CLOB class
- this.clobClass = con.getClass().getClassLoader().loadClass(CLOB_CLASS_NAME);
- this.durationSessionConstants.put(
- this.clobClass, new Integer(this.clobClass.getField(DURATION_SESSION_FIELD_NAME).getInt(null)));
- this.modeReadWriteConstants.put(
- this.clobClass, new Integer(this.clobClass.getField(MODE_READWRITE_FIELD_NAME).getInt(null)));
- }
- catch (Exception ex) {
- throw new InvalidDataAccessApiUsageException(
- "Couldn't initialize OracleLobHandler because Oracle driver classes are not available. " +
- "Note that OracleLobHandler requires Oracle JDBC driver 9i or higher!", ex);
- }
- }
- }
- //委托给Blob接口;
- public byte[] getBlobAsBytes(ResultSet rs, int columnIndex) throws SQLException {
- logger.debug("Returning Oracle BLOB as bytes");
- Blob blob = rs.getBlob(columnIndex);
- return (blob != null ? blob.getBytes(1, (int) blob.length()) : null);
- }
- public InputStream getBlobAsBinaryStream(ResultSet rs, int columnIndex) throws SQLException {
- logger.debug("Returning Oracle BLOB as binary stream");
- Blob blob = rs.getBlob(columnIndex);
- return (blob != null ? blob.getBinaryStream() : null);
- }
- public String getClobAsString(ResultSet rs, int columnIndex) throws SQLException {
- logger.debug("Returning Oracle CLOB as string");
- Clob clob = rs.getClob(columnIndex);
- return (clob != null ? clob.getSubString(1, (int) clob.length()) : null);
- }
- public InputStream getClobAsAsciiStream(ResultSet rs, int columnIndex) throws SQLException {
- logger.debug("Returning Oracle CLOB as ASCII stream");
- Clob clob = rs.getClob(columnIndex);
- return (clob != null ? clob.getAsciiStream() : null);
- }
- public Reader getClobAsCharacterStream(ResultSet rs, int columnIndex) throws SQLException {
- logger.debug("Returning Oracle CLOB as character stream");
- Clob clob = rs.getClob(columnIndex);
- return (clob != null ? clob.getCharacterStream() : null);
- }
- public LobCreator getLobCreator() {
- return new OracleLobCreator();
- }
- //内部类,具体的Lob工厂,能够生成Oracle的Lob对象;
- protected class OracleLobCreator implements LobCreator {
- private final List createdLobs = new LinkedList();
- public void setBlobAsBytes(PreparedStatement ps, int paramIndex, final byte[] content)
- throws SQLException {
- if (content != null) {
- Blob blob = (Blob) createLob(ps, false, new LobCallback() {
- public void populateLob(Object lob) throws Exception {
- Method methodToInvoke = lob.getClass().getMethod("getBinaryOutputStream", new Class[0]);
- OutputStream out = (OutputStream) methodToInvoke.invoke(lob, (Object[]) null);
- FileCopyUtils.copy(content, out);
- }
- });
- ps.setBlob(paramIndex, blob);
- if (logger.isDebugEnabled()) {
- logger.debug("Set bytes for Oracle BLOB with length " + blob.length());
- }
- }
- else {
- ps.setBlob(paramIndex, null);
- logger.debug("Set Oracle BLOB to null");
- }
- }
- public void setBlobAsBinaryStream(
- PreparedStatement ps, int paramIndex, final InputStream binaryStream, int contentLength)
- throws SQLException {
- if (binaryStream != null) {
- Blob blob = (Blob) createLob(ps, false, new LobCallback() {
- public void populateLob(Object lob) throws Exception {
- ///生成一个空的Blob对象以后,用getBinaryOutputStream得到一个输出流,从一个二进制输入流中将流输出到Blob对象中;前后调用的Open和Close方法就是关闭流的操作;
- Method methodToInvoke = lob.getClass().getMethod("getBinaryOutputStream", (Class[]) null);
- OutputStream out = (OutputStream) methodToInvoke.invoke(lob, (Object[]) null);
- FileCopyUtils.copy(binaryStream, out);
- }
- });
- ps.setBlob(paramIndex, blob);
- if (logger.isDebugEnabled()) {
- logger.debug("Set binary stream for Oracle BLOB with length " + blob.length());
- }
- }
- else {
- ps.setBlob(paramIndex, null);
- logger.debug("Set Oracle BLOB to null");
- }
- }
- public void setClobAsString(PreparedStatement ps, int paramIndex, final String content)
- throws SQLException {
- if (content != null) {
- Clob clob = (Clob) createLob(ps, true, new LobCallback() {
- public void populateLob(Object lob) throws Exception {
- Method methodToInvoke = lob.getClass().getMethod("getCharacterOutputStream", (Class[]) null);
- Writer writer = (Writer) methodToInvoke.invoke(lob, (Object[]) null);
- FileCopyUtils.copy(content, writer);
- }
- });
- ps.setClob(paramIndex, clob);
- if (logger.isDebugEnabled()) {
- logger.debug("Set string for Oracle CLOB with length " + clob.length());
- }
- }
- else {
- ps.setClob(paramIndex, null);
- logger.debug("Set Oracle CLOB to null");
- }
- }
- public void setClobAsAsciiStream(
- PreparedStatement ps, int paramIndex, final InputStream asciiStream, int contentLength)
- throws SQLException {
- if (asciiStream != null) {
- Clob clob = (Clob) createLob(ps, true, new LobCallback() {
- public void populateLob(Object lob) throws Exception {
- Method methodToInvoke = lob.getClass().getMethod("getAsciiOutputStream", (Class[]) null);
- OutputStream out = (OutputStream) methodToInvoke.invoke(lob, (Object[]) null);
- FileCopyUtils.copy(asciiStream, out);
- }
- });
- ps.setClob(paramIndex, clob);
- if (logger.isDebugEnabled()) {
- logger.debug("Set ASCII stream for Oracle CLOB with length " + clob.length());
- }
- }
- else {
- ps.setClob(paramIndex, null);
- logger.debug("Set Oracle CLOB to null");
- }
- }
- public void setClobAsCharacterStream(
- PreparedStatement ps, int paramIndex, final Reader characterStream, int contentLength)
- throws SQLException {
- if (characterStream != null) {
- Clob clob = (Clob) createLob(ps, true, new LobCallback() {
- public void populateLob(Object lob) throws Exception {
- Method methodToInvoke = lob.getClass().getMethod("getCharacterOutputStream", (Class[]) null);
- Writer writer = (Writer) methodToInvoke.invoke(lob, (Object[]) null);
- FileCopyUtils.copy(characterStream, writer);
- }
- });
- ps.setClob(paramIndex, clob);
- if (logger.isDebugEnabled()) {
- logger.debug("Set character stream for Oracle CLOB with length " + clob.length());
- }
- }
- else {
- ps.setClob(paramIndex, null);
- logger.debug("Set Oracle CLOB to null");
- }
- }
- /**
- * Create a LOB instance for the given PreparedStatement,
- * populating it via the given callback.
- */
- protected Object createLob(PreparedStatement ps, boolean clob, LobCallback callback)
- throws SQLException {
- Connection con = null;
- try {
- con = getOracleConnection(ps);
- initOracleDriverClasses(con);
- Object lob = prepareLob(con, clob ? clobClass : blobClass);
- callback.populateLob(lob);
- ///lob.close();
- lob.getClass().getMethod("close", (Class[]) null).invoke(lob, (Object[]) null);
- //利用这个工厂所生产出来的连接会在工厂关闭时进行统一的freeTemporary方法调用;
- this.createdLobs.add(lob);
- if (logger.isDebugEnabled()) {
- logger.debug("Created new Oracle " + (clob ? "CLOB" : "BLOB"));
- }
- return lob;
- }
- catch (SQLException ex) {
- throw ex;
- }
- catch (InvocationTargetException ex) {
- if (ex.getTargetException() instanceof SQLException) {
- throw (SQLException) ex.getTargetException();
- }
- else if (con != null && ex.getTargetException() instanceof ClassCastException) {
- throw new InvalidDataAccessApiUsageException(
- "OracleLobCreator needs to work on [oracle.jdbc.OracleConnection], not on [" +
- con.getClass().getName() + "]: specify a corresponding NativeJdbcExtractor",
- ex.getTargetException());
- }
- else {
- throw new DataAccessResourceFailureException("Could not create Oracle LOB",
- ex.getTargetException());
- }
- }
- catch (Exception ex) {
- throw new DataAccessResourceFailureException("Could not create Oracle LOB", ex);
- }
- }
- /**
- * 抽取连接.
- */
-
- protected Connection getOracleConnection(PreparedStatement ps)
- throws SQLException, ClassNotFoundException {
- return (nativeJdbcExtractor != null) ?
- nativeJdbcExtractor.getNativeConnectionFromStatement(ps) : ps.getConnection();
- }
- /**
- * Create and open an oracle.sql.BLOB/CLOB instance via reflection.
- */
- protected Object prepareLob(Connection con, Class lobClass) throws Exception {
- /*
- BLOB blob = BLOB.createTemporary(con, false, BLOB.DURATION_SESSION);
- blob.open(BLOB.MODE_READWRITE);
- return blob;
- */
- Method createTemporary = lobClass.getMethod(
- "createTemporary", new Class[] {Connection.class, boolean.class, int.class});
- Object lob = createTemporary.invoke(
- null, new Object[] {con, cache, durationSessionConstants.get(lobClass)});
- Method open = lobClass.getMethod("open", new Class[] {int.class});
- open.invoke(lob, new Object[] {modeReadWriteConstants.get(lobClass)});
- return lob;
- }
- /**
- * Free all temporary BLOBs and CLOBs created by this creator.
- */
- public void close() {
- try {
- for (Iterator it = this.createdLobs.iterator(); it.hasNext();) {
- /*
- BLOB blob = (BLOB) it.next();
- blob.freeTemporary();
- */
- Object lob = it.next();
- Method freeTemporary = lob.getClass().getMethod("freeTemporary", new Class[0]);
- freeTemporary.invoke(lob, new Object[0]);
- it.remove();
- }
- }
- catch (InvocationTargetException ex) {
- logger.error("Could not free Oracle LOB", ex.getTargetException());
- }
- catch (Exception ex) {
- throw new DataAccessResourceFailureException("Could not free Oracle LOB", ex);
- }
- }
- }
- /**
- * Internal callback interface for use with createLob.
- */
- protected static interface LobCallback {
- /**
- * Populate the given BLOB or CLOB instance with content.
- * @throws Exception any exception including InvocationTargetException
- */
- void populateLob(Object lob) throws Exception;
- }
- }
- BLOB blob = BLOB.createTemporary(con, false, BLOB.DURATION_SESSION);
- blob.open(BLOB.MODE_READWRITE);
- return blob;
至于如何插入Blob,Clob对象,那么就跟我们开始看见的一样,必须用到LobCreater工厂生产出大对象;
- private void execute saveImage(String description,byte[] content,int id){
- this.getJdbcTemplate().execute("insert into IMAGES(id,description,content)", new AbstractLobCreatingPreparedStatementCallback(this.lobHandler){
- @Override
- protected void setValues(PreparedStatement ps, LobCreator lobCreator)
- throws SQLException, DataAccessException {
- ps.setInt(1, id);
- lobCreator.setClobAsString(ps, 2, description);
- lobCreator.setBlobAsBytes(ps, 3, content);
- }
- });
- }
- public abstract class AbstractLobCreatingPreparedStatementCallback implements PreparedStatementCallback {
- private final LobHandler lobHandler;
- public AbstractLobCreatingPreparedStatementCallback(LobHandler lobHandler) {
- this.lobHandler = lobHandler;
- }
- public final Object doInPreparedStatement(PreparedStatement ps) throws SQLException, DataAccessException {
- LobCreator lobCreator = this.lobHandler.getLobCreator();
- try {
- setValues(ps, lobCreator);
- return new Integer(ps.executeUpdate());
- }
- finally {
- lobCreator.close();
- }
- }
- protected abstract void setValues(PreparedStatement ps, LobCreator lobCreator)
- throws SQLException, DataAccessException;
- }
这时,我们切换数据库的时候,不用再修改源代码,把Oracle.sql.BLOB修改成为om.mysql.jdbc.Blob了,我们只要修改注入到dao中的LobHandler就可以啦;
这篇关于Spring源代码分析(13)---BLOB和CLOB操作(不是大就了不起)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!