JDBC大数据处理和数据库隔离级别   Leave a comment

一段对Date类型数据数据库存储的操作

这的Date是java.util.Date类型,后面对数据库的Date操作的是java.sql.Date。由于java.sql.Date是java.util.Date的子类,所以无法把java.util.Date对象直接赋值给java.sql.Date(父类不能代替子类)

static void create(String name, Date birthday, float money)

                     throws SQLException {

              Connection conn = null;

              PreparedStatement ps = null;

              ResultSet rs = null;

              try {

                     // 2.建立连接

                     conn = JdbcUtils.getConnection();

                     // conn = JdbcUtilsSing.getInstance().getConnection();

                     // 3.创建语句

                     String sql = "insert into user(name,birthday, money) values (?, ?, ?) ";

                     ps = conn.prepareStatement(sql);

                     ps.setString(1, name);

传入的birthday是java.util.Date类型,这里把它转化成它的子类java.sql.Date类型

                     ps.setDate(2, new java.sql.Date(birthday.getTime()));

                     ps.setFloat(3, money);

                     // 4.执行语句

                     int i = ps.executeUpdate();

                     System.out.println("i=" + i);

              } finally {

                     JdbcUtils.free(rs, ps, conn);

              }

       }

大文本文件数据库读写

数据库中的varchar类型最大只能有255个字符,如果遇上需要保存大的文本文件,就需要使用数据库中的text类型字段。

     CLOB  text

       存:ps.setCharacterStream(index, reader, length);

                ps.setString(i, s);

       取:reader = rs. getCharacterStream(i);

                reader = rs.getClob(i).getCharacterStream();

                string = rs.getString(i);

关于大文件数据库读写的操作方式:

从外界读入数据进数据库

            // 2.建立连接

                     conn = JdbcUtils.getConnection();

                     // conn = JdbcUtilsSing.getInstance().getConnection();

                     // 3.创建语句

                     String sql = "insert into clob_test(big_text) values (?) ";

                     ps = conn.prepareStatement(sql);

获得需要输入的文件的对象

                     File file = new File("src/cn/itcast/jdbc/JdbcUtils.java");

把文件转化成reader流对象

                     Reader reader = new BufferedReader(new FileReader(file));

把这个流对象保存进数据库

                     ps.setCharacterStream(1, reader, (int) file.length());

                     // ps.setString(1, x);

                     // 4.执行语句

                     int i = ps.executeUpdate();

关闭流

                     reader.close();

从数据库中读取text文件

                rs = st.executeQuery("select big_text from clob_test");  

从数据库中获得保存大文件的字段对象   

                Clob clob = rs.getClob(1);

获得这个字段中数据的Reader流对象

                            Reader reader = clob.getCharacterStream();

                            // reader = rs.getCharacterStream(1);

                            // String s = rs.getString(1);

创建一个文件和一个Writer流,把Reader中的数据全部写入到这个文件

                            File file = new File("JdbUtils_bak.java");

                            Writer writer = new BufferedWriter(new FileWriter(file));

                            char[] buff = new char[1024];

每次从reader流对象中读取数据,返回的i就是读取到的字符个数,如果i=0,就是读完了

                            for (int i = 0; (i = reader.read(buff)) > 0;) {

由于读取到最后一次的时候buff数组可能不满,这么做可以保证每次写入的数据都是有效的

                                   writer.write(buff, 0, i);

                            }

                            writer.close();

                            reader.close();

对字节流的读取

当所需要读取的文件是个图片或者java的包,这个时候文本的读取方式就不行了,只能使用字节流来读取。数据库中对应保存这种数据的数据类型是BLOB

.BLOB  blob

       存:ps.setBinaryStream(i, inputStream, length);

     取:rs.getBinaryStream(i);

            rs.getBlob(i).getBinaryStream();

下面是对于字节流数据库存取操作

// 2.建立连接

                     conn = JdbcUtils.getConnection();

                     // conn = JdbcUtilsSing.getInstance().getConnection();

                     // 3.创建语句

                     String sql = "insert into blob_test(big_bit) values (?) ";

                     ps = conn.prepareStatement(sql);

                     File file = new File("IMG_0002.jpg");

这里是二进制文件,所以必须使用这个,不能使用read了

                     InputStream in = new BufferedInputStream(new FileInputStream(file));

                     ps.setBinaryStream(1, in, (int) file.length());

                     // 4.执行语句

                     int i = ps.executeUpdate();

                     in.close();

从数据库中读出二进制文件

                // Blob blob = rs.getBlob(1);

                            // InputStream in = blob.getBinaryStream();

从数据库中读取文件的流对象

                            InputStream in = rs.getBinaryStream("big_bit");

                            File file = new File("IMG_0002_bak.jpg");

                            OutputStream out = new BufferedOutputStream(

                                          new FileOutputStream(file));

                            byte[] buff = new byte[1024];

                            for (int i = 0; (i = in.read(buff)) > 0;) {

                                   out.write(buff, 0, i);

                            }

                            out.close();

                            in.close();

工厂模式经典代码

public class DaoFactory {

       private static UserDao userDao = null;

       private static DaoFactory instance = new DaoFactory();

       private DaoFactory() {

              try {

                     Properties prop = new Properties();

注意这里读取配置文件的方法,使用ClassLoader来获得配置文件的输入流对象,只要这个文件在这个ClassLoader所能控制的目录结构里,就一定能够找到它。我们这里使用的类加载器可以加载到任何在classpath中的类和文件

                     InputStream inStream = DaoFactory.class.getClassLoader()

                                   .getResourceAsStream("daoconfig.properties");

                     prop.load(inStream);

                     String userDaoClass = prop.getProperty("userDaoClass");

                     Class clazz = Class.forName(userDaoClass);

                     userDao = (UserDao) clazz.newInstance();

              } catch (Throwable e) {

                     throw new ExceptionInInitializerError(e);

              }

       }

       public static DaoFactory getInstance() {

              return instance;

       }

       public UserDao getUserDao() {

              return userDao;

       }

}

事务(ACID)

原子性(atomicity):组成事务处理的语句形成了一个逻辑单元,不能只执行其中的一部分。

一致性(consistency):在事务处理执行前后,数据库是一致的(数据库数据完整性约束)。

隔离性(isolcation):一个事务处理对另一个事务处理的影响。

持续性(durability):事务处理的效果能够被永久保存下来 。

connection.setAutoCommit(false);//打开事务。不使用事务的自动提交

connection.commit();//提交事务。

connection.rollback();//回滚事务。

一段事务相关的代码

try {

                     conn = JdbcUtils.getConnection();

开启事务,把事务的自动提交关闭

                     conn.setAutoCommit(false);

              设置隔离级别       conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);

                    

                     st = conn.createStatement();

                     String sql = "update user set money=money-10 where id=1";

                     st.executeUpdate(sql);

                     sql = "select money from user where id=2";

                     rs = st.executeQuery(sql);

                     float money = 0.0f;

                     if (rs.next()) {

                            money = rs.getFloat("money");

                     }

                     if (money > 400)

对于不知道该如何处理的异常都用运行时异常抛出

                            throw new RuntimeException("已经超过最大值!");

                     sql = "update user set money=money+10 where id=2";

                     st.executeUpdate(sql);

提交事务

                     conn.commit();

              } catch (SQLException e) {

                     if (conn != null)

发生异常的时候事务回滚

                            conn.rollback();

                     throw e;

              } finally {

                     JdbcUtils.free(rs, st, conn);

              }

事务中的保存点

当只想撤销事务中的部分操作时可使用SavePoint

SavePoint sp = connection.setSavepoint();

如果rollerbak中没有参数,就把整个事务回滚,如果传入了一个保存点SavePoint 对象,保存点以前部分不会被回滚

connection.rollerbak(sp);connection.commit();

隔离级别多线程并发读取数据时的正确性

connection.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);

V:可能出现,X:不会出现

脏读:读到用户没有被事务提交的数据,

不可重复读:在同一个事务的读取过程中,数据发生变化,比如第一次读以后,别的线程插入新的数据,所以下次读取的时候发现数据发生变化。

可重复读:在一个事务读取数据库过程中,即便另外一个线程修改了数据库并且提交了。在当前这个事务没有关闭前,每次读取到的数据都是一样的,不会受另外一个线程提交的数据影响。

幻读:在“可重复读”情况下,有时候会出现:在Thread1中开启事务,当另外一个线程Thread2事务已经关闭,但是利用数据库本身默认设置的自动提交,在没有开启事务的情况下往数据库中修改数据,这种修改也可以成功。这个时候,Thread1线程有时候就会读到这种数据,这就是幻读。

如果数据库是“Serializable可串行化”的话,假设在Thread1一个事务开启以后,另外一个线程Thread2线程如果想修改数据库中的数据,这个Thread2修改线程会挂起无法完成,直到Thread1线程事务提交以后,Thread2的修改操作才能完成。

“Serializable可串行化”这种级别一次只准许一个人修改数据,其他线程只能查询,但是不能进行任何修改。

Posted 2009年12月8日 by gw8310 in 未分类

发表评论

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 更改 )

Twitter picture

You are commenting using your Twitter account. Log Out / 更改 )

Facebook photo

You are commenting using your Facebook account. Log Out / 更改 )

Google+ photo

You are commenting using your Google+ account. Log Out / 更改 )

Connecting to %s

%d 博主赞过: