08第十天JDBC开发

it2026-05-08  8

一、JDBC: Java DataBase Connectivity   (一)、JDBC基础         1、 数据库驱动: 数据库厂商为了方便开发人员从程序中操作数据库而提供的一套jar包,通过导入这个jar包就可以调用其中的方法操作数据库,这样的jar包就叫做数据库驱动。        2、JDBC:两个包,包括 java.sql和 javax.sql。开发JDBC应用需要以上2个包的支持外,还需要导入相应JDBC的数据库实现(即数据库驱动)。 sun定义的一套标准,本质上是一大堆的 操作数据库的接口,所有数据库厂商为java设计的数据库驱动都实现过这套接口,这样一来同一了不同数据库驱动的方法,开发人员只需要学习JDBC就会使用任意数据库驱动了。   (二)、JDBC实现          1、新建Java项目-->新建lib文件夹-->导入mysql-connector-java-5.1.40-bin.jar-->邮右键build path  -->add to build path--》新建类。                            六个步骤实现JDBC package com.lmd.jdbc;//接口,面向接口编程,更换数据库不变,通用性import java.sql.Connection; import java.sql.DriverManager;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Statement;//mysql做的实现import com.mysql.jdbc.Driver;public class JDBCDemo1 { public static void main(String[] args) throws SQLException{ //1.注册数据库驱动 DriverManager.registerDriver(new Driver()); //Class.forName("com.mysql.jdbc.Driver"); //2.获取数据库连接 String url = "jdbc:mysql://localhost:3306/day10"; Connection con = DriverManager.getConnection(url, "root", "666666"); //Connection con = DriverManager.getConnection(url + //"?user=root&password=666666"); //Connection con = DriverManager.getConnection("jdbc:mysql:/// //day10?user=root&password=666666"); //3.获取传输器对象 Statement st = con.createStatement(); //4.利用传输器传输sql语句到数据库中执行,获取结果集对象 ResultSet rs = st.executeQuery("select * from user"); //5.遍历结果集获取查询结果 while(rs.next()){ String name = rs.getString("name"); System.out.println(name); } //6.关闭资源 rs.close(); st.close(); con.close(); }}        2、 DriverManager              (1)、Jdbc程序中的DriverManager用于加载驱动,并创建与数据库的链接,这个API的常用方法:                             DriverManager.registerDriver(new Driver());                             DriverManager.getConnection(url, user, password);               注意:在实际开发中并 不推荐采用registerDriver方法注册驱动。原因有二:                1)、查看Driver的源代码可以看到,如果采用此种方式,会导致驱动程序 注册两次,也就是在内存中会有两个Driver对象。                2)、程序依赖mysql的api,脱离mysql的jar包,程序将无法编译,将来程序切换底层数据库将会非常麻烦。 创建mysql的Driver对象,导致程序和具体的mysql驱动绑死在一起,在切换数据库时需改动JAVA代码。 package com.mysql.jdbc;import java.sql.SQLException;public class Driver extends NonRegisteringDriver implements java.sql.Driver { // Register ourselves with the DriverManager static { try { java.sql.DriverManager.registerDriver(new Driver()); } catch (SQLException E) { throw new RuntimeException("Can't register driver!"); } } public Driver() throws SQLException { // Required for Class.forName().newInstance() }}              (2)、推荐方式: Class.forName(“com.mysql.jdbc.Driver”);            采用此种方式不会导致驱动对象在内存中重复出现,并且采用此种方式,程序仅仅只需要一个字符串,不需要依赖具体的驱动,使程序的灵活性更高。          同样,在开发中也 不建议采用具体的驱动类型指向 getConnection方法返回的connection对象。        3、 数据库URL           URL用于标识数据库的位置,程序员通过URL地址告诉JDBC程序连接哪个数据库,URL的写法为: 常用数据库URL地址的写法: Oracle写法:jdbc:oracle:thin:@localhost:1521:sid SqlServerjdbc:microsoft:sqlserver://localhost:1433; DatabaseName=sid MySqljdbc:mysql://localhost:3306/sidMysqlurl地址的简写形式: jdbc:mysql:///sid常用属性:useUnicode=true&characterEncoding=UTF-8         4、程序详解—Connection          Jdbc程序中的Connection,它用于代表数据库的链接,Connection是数据库编程中最重要的一个对象,客户端与数据库所有交互都是通过connection对象完成的,这个对象的常用方法: ResultSet createStatement():创建向数据库发送sqlstatement对象。PrepareStatement prepareStatement(sql) :创建向数据库发送预编译sqlPrepareSatement对象。CallableStatement prepareCall(sql):创建执行存储过程的callableStatement对象。 void setAutoCommit(boolean autoCommit):设置事务是否自动提交。 void commit() :在链接上提交事务。void rollback() :在此链接上回滚事务。                 5、程序详解— Statement          Jdbc程序中的Connection,它用于代表数据库的链接,Connection是数据库编程中最重要的一个对象,客户端与数据库所有交互都是通过connection对象完成的,这个对象的常用方法: ResultSet executeQuery(String sql) :用于向数据发送查询语句。 int executeUpdate(String sql):用于向数据库发送insertupdatedelete语句boolean execute(String sql):用于向数据库发送任意sql语句void addBatch(String sql) :把多条sql语句放到一个批处理中。int[] executeBatch():向数据库发送一批sql语句执行。        6 、程序详解—ResultSet         (1)、 Jdbc程序中的ResultSet用于代表Sql语句的执行结果。Resultset封装执行结果时,采用的类似于表格的方式。ResultSet 对象维护了一个指向表格数据行的游标,初始的时候,游标在第一行之前,调用ResultSet.next() 方法,可以使游标指向具体的数据行,进行调用方法获取该行的数据。         (2)、ResultSet既然用于封装执行结果的,所以该对象提供的都是用于获取数据的get方法: 获取任意类型的数据 getObject(int index) getObject(string columnName)获取指定类型的数据,例如: getString(int index) getString(String columnName)     ResultSet还提供了对结果集进行滚动的方法: boolean next():移动到下一行 boolean previous():移动到前一行 boolean absolute(int row):移动到指定行 void beforeFirst():移动resultSet的最前面。 void afterLast() :移动到resultSet的最后面。 例如: 表中:zs lisi wangwurs.next(); rs.next(); 打印:lisirs.previous();//zsrs.absolute(3);//wangwu 第三行String name = rs.getString("name");System.out.println(name);        7 、程序详解—释放资源         (1)、Jdbc程序运行完后,切记要释放程序在运行过程中,创建的那些与数据库进行交互的对象, 这些对象通常是ResultSet、Statement和Connection对象。         (2)、特别是Connection对象,它是非常稀有的资源,用完后必须马上释放,如果Connection不能及时、正确的关闭, 极易 导致系统宕机。Connection的使用原则是尽量晚创建,尽量早的释放。         (3)、为确保资源释放代码能运行,资源释放代码也一定要放在finally语句中。         若 if (rs != null)  rs.close();  加到 try...catch...中,后面要加一个 rs=null;  变成垃圾对象被回收。完整的如下: public class JDBCDemo1 { public static void main(String[] args){ Connection conn = null; Statement stat = null; ResultSet rs = null; try { Class.forName("com.mysql.jdbc.Driver"); String url = "jdbc:mysql://localhost:3306/day10"; conn = DriverManager.getConnection(url, "root", "666666"); stat = conn.createStatement(); rs = stat.executeQuery("select * from user"); while(rs.next()){ String name = rs.getString("name"); System.out.println(name); } } catch (Exception e) { e.printStackTrace(); } finally { if (rs != null) { try { rs.close(); } catch (SQLException e) { e.printStackTrace(); }finally { rs = null; } } if (stat != null) { try { stat.close(); } catch (SQLException e) { e.printStackTrace(); }finally { stat = null; } } if (conn != null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); }finally { conn = null; } } } }}   (三)、JDBC增删改查 create database day10 character set utf8 collate utf8_general_ci;use day10;create table user( id int primary key auto_increment, name varchar(40), password varchar(40), email varchar(60), birthday date)character set utf8 collate utf8_general_ci;insert into user(name,password,email,birthday) values('zs','123456','zs@sina.com','1980-12-04');insert into user(name,password,email,birthday) values('lisi','123456','lisi@sina.com','1981-12-04');insert into user(name,password,email,birthday) values('wangwu','123456','wangwu@sina.com','1979-12-04'); mysql> select * from user;+----+--------+----------+-----------------+------------+| id | name | password | email | birthday |+----+--------+----------+-----------------+------------+| 1 | zs | 123456 | zs@sina.com | 1980-12-04 || 2 | lisi | 123456 | lisi@sina.com | 1981-12-04 || 3 | wangwu | 123456 | wangwu@sina.com | 1979-12-04 |+----+--------+----------+-----------------+------------+ package com.lmd.util;import java.io.FileNotFoundException/FileReader;import java.sql.Connection/DriverManager/ResultSet;import java.sql.SQLException/Statement;import java.util.Properties;public class JDBCUtils { private static Properties prop = null; private JDBCUtils(){ } //只解析一次,放在静态代码块里 static{ prop = new Properties(); try { prop.load(new FileReader(JDBCUtils.class.getClassLoader(). getResource("config.properties").getPath())); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } } /** * 获取连接 * @return * @throws ClassNotFoundException * @throws SQLException */ public static Connection getConn() throws ClassNotFoundException, SQLException{ //1、注册数据库驱动 Class.forName(prop.getProperty("driver")); //2、获取连接 return DriverManager.getConnection(prop.getProperty("url"), prop.getProperty("username"), prop.getProperty("password")); } /** * 关闭连接 * @param rs * @param stat * @param conn */ public static void close(ResultSet rs, Statement stat, Connection conn) { if (rs != null) { try { rs.close(); } catch (SQLException e) { e.printStackTrace(); }finally { rs = null; } } if (stat != null) { try { stat.close(); } catch (SQLException e) { e.printStackTrace(); }finally { stat = null; } } if (conn != null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); }finally { conn = null; } } }} 配置文件:config.properties 在src下driver=com.mysql.jdbc.Driverurl=jdbc:mysql://localhost:3306/day10username=rootpassword=66666         1、使用executeUpdate(String sql)方法完成数据添加操作,示例操作: @Test public void add(){ Connection conn = null; Statement stat = null; try { //1、注册数据库驱动;2、获取数据库连接 conn = JDBCUtils.getConn(); //3、获取传输器对象 stat = conn.createStatement(); //4、利用传输器传输sql语句到数据库中执行,获取结果集对象 int count = stat.executeUpdate("insert into user values(null,'lily','666666' ,'lily8@163.com','1990-12-22')"); //5、处理结果 if (count>0) { System.out.println("执行成功!影响到的行数为"+count); } else { System.out.println("执行失败!"); } } catch (Exception e) { e.printStackTrace(); } finally { //6、关闭连接 JDBCUtils.close(null, stat, conn); } } 结果如下:          2 、使用executeUpdate(String sql)方法完成数据修改操作,示例操作: public void update(){ Connection conn = null; Statement stat = null; try { conn = JDBCUtils.getConn(); stat = conn.createStatement(); stat.executeUpdate("update user set password='888888' where id=2"); } catch (Exception e) { e.printStackTrace(); } finally { //6、关闭连接 JDBCUtils.close(null, stat, conn); } } 结果如下:          3 、使用executeQuery(String sql)方法完成数据查询操作,示例操作: @Test public void find(){ Connection conn = null; Statement stat = null; ResultSet rs = null; try { conn = JDBCUtils.getConn(); stat = conn.createStatement(); rs = stat.executeQuery("select * from user where name='lily'"); while (rs.next()) { String name = rs.getString("name"); String password = rs.getString("password"); System.out.println(name+":"+password); } } catch (Exception e) { e.printStackTrace(); } finally { //6、关闭连接 JDBCUtils.close(null, stat, conn); } } 结果如下:         4 、使用  executeUpdate(String sql)方法完成数据删除操作,示例操作: @Test public void delete(){ Connection conn = null; Statement stat = null; try { conn = JDBCUtils.getConn(); stat = conn.createStatement(); stat.executeUpdate("delete from user where name='lily'"); } catch (Exception e) { e.printStackTrace(); } finally { //6、关闭连接 JDBCUtils.close(null, stat, conn); } } 结果如下:     (四)、案例:改写前面讲解的用户注册和登陆案例,实现如下需求: 1、把xml换成数据库,重写XmlUserDao2、定义DAO接口,并定义Dao工厂,实现service层和dao层的解耦。3、自定义dao异常。4、防范sql注入攻击         一、为什么:要分层 使软件具有结构性,便于开发、维护和管理。 将不同功能模块独立,在需要替换某一模块时不需要改动其他模块,方便代码的复用、替换二、层与层耦合的概念,利用工厂类解耦 在分层结构中,我们希望将各个功能 约束在各自的模块(层)当中的,而当属于某一层的对象、方法“入侵”到了其他层,如将web层的ServletContext对象传入service层,或service层调用XMLDao独有的方法,就会导致层与层之间的关系过于“紧密”,当需要修改某一层时不可避免的要修改其他关联的层,这和我们软件分层最初的设想-----层与层分离,一个层尽量不依赖其他层存在,当修改一层时无需修改另一层的设想是违背的。这种“入侵”造成的“紧密”关系就早做层与层之间发生的“耦合”,而去掉这种耦合性的过程就叫做层与层之间“解耦” 利用工厂类可以实现解耦的功能三、如何判断一项功能到底属于哪一层 某一项功能属于哪一层,往往是不能明确确定出来的,这时可以参考如下标准进行判断: 1、此项功能在业务逻辑上更贴近与哪一层,放在哪一层更能较少耦合 2、此项功能是否必须使用某一层特有的对象 3、如果放在哪一层都可以,那么放在哪一层更方便技术上的实现,及方便代码的编写和维护 四、异常的处理 1、如果一个异常抛给上一层会增加程序的耦合性,请当场解决:如将xml解析错误抛给service层,那么当换成mysqldao时, 还需要修改service去掉xml解析异常的处理。 2、如果上一层明确需要此异常进行代码的流转,请抛出:如当查找一个用户信息而用户找不到时, 可以抛出一个用户找不到异常,明确要求上一层处理。 3、如果这一层和上一层都能解决尽量在这一层解决掉。 4、如果这一层不能解决,而上一层能解决抛给上一层。 5、如果所有层都不能解决,则应抛出给虚拟机使线程停止,但是如果直接抛出这个异常,则还需要调用者一级一级继续 往上抛出最后才能抛给虚拟机,所以还不如在出现异常的位置直接try...catch住后转换为RuntimeException抛出。 :如读取配置文件出错,任何层都不能解决,转为RuntimeException抛出,停止线程。 1、改写案例 (1)、把xml换成数据库,重写XmlUserDao。 create table users( id int primary key auto_increment, username varchar(20), password varchar(50), nickname varchar(40), email varchar(50));insert into users values(null,'admin','admin','admin','admin8@qq.com');   (2)、 重写XmlUserDao,改为 MysqlUserDao.java。 1)、将XmlUserDao中的方法定义到一个接口中,注意:   使用接口定义使用的三个方法;接口一定要有注释,并且是文档注释。 方法注释一方都放在接口中,而非实现类中。 在接口中使用接口注释后,当鼠标移到实现类中方法上就会有提示。 package com.lmd.dao;import com.lmd.domain.User;public interface UserDao { /** * 根据用户名查找用户 * @param username 用户名 * @return 根据用户名找到的用户信息bean,若没找到返回null */ public User findUserByUserName(String username); /** * 添加用户 * @param user 要添加的用户信息bean */ public void addUser(User user); /** * 根据用户名和密码查找对应的用户 * @param username 用户名 * @param password 密码 * @return 找到的用户,若没找到返回null */ public User findUserByUNandPSW(String username, String password);} 2)、仍需要前面设置的config.properties和JDBCUtils.java,开发MysqlUserDao.java:                修改User.java,增加id;修改UserService.java一句话。 //private XmlUserDao dao = new XmlUserDao(); private MysqlUserDao dao = new MysqlUserDao(); 这个切换数据库会改变代码,不太好,后面会讲怎么办? 这是一种耦合,后面会 利用工厂类实现解耦 package com.lmd.dao;import java.sql.Connection;import java.sql.ResultSet;import java.sql.Statement;import com.lmd.domain.User;import com.lmd.util.JDBCUtils;public class MysqlUserDao implements UserDao{ @Override public User findUserByUserName(String username) { String sql = "select * from users where username='"+username+"'"; Connection conn = null; Statement stat = null; ResultSet rs = null; try { conn = JDBCUtils.getConn(); stat = conn.createStatement(); rs = stat.executeQuery(sql); if (rs.next()) { User user = new User(); user.setId(rs.getInt("id")); user.setUsername(rs.getString("username")); user.setPassword(rs.getString("password")); user.setNickname(rs.getString("nickname")); user.setEmail(rs.getString("email")); return user; } else { return null; } } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } finally { JDBCUtils.close(rs, stat, conn); } } @Override public void addUser(User user) { String sql = "insert into users values (null,'"+user.getUsername()+ "','"+user.getPassword()+"','"+user.getNickname()+"','"+user.getEmail()+"')"; Connection conn = null; Statement stat = null; try { conn = JDBCUtils.getConn(); stat = conn.createStatement(); stat.executeUpdate(sql); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } finally { JDBCUtils.close(null, stat, conn); } } @Override public User findUserByUNandPSW(String username, String password) { String sql = "select * from users where username='"+username+"' and password='"+password+"'"; Connection conn = null; Statement stat = null; ResultSet rs = null; try { conn = JDBCUtils.getConn(); stat = conn.createStatement(); rs = stat.executeQuery(sql); if (rs.next()) { User user = new User(); user.setId(rs.getInt("id")); user.setUsername(rs.getString("username")); user.setPassword(rs.getString("password")); user.setNickname(rs.getString("nickname")); user.setEmail(rs.getString("email")); return user; } else { return null; } } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } finally { JDBCUtils.close(rs, stat, conn); } } }          2、 定义DAO接口,并定义Dao工厂,实现service层和dao层的解耦。 package com.lmd.factory;import java.io.FileReader;import java.util.Properties;import com.lmd.dao.UserDao;/** * 单例模式:保证在整个应用程序的生命周期中, * 任何一个时刻,单例类的实例只存在一个(也可以不存在) * @author angel11288 * */public class DaoFactory { private static DaoFactory factory = new DaoFactory(); //配置文件只读一次 private static Properties prop = null; static{ try { prop = new Properties(); prop.load(new FileReader(DaoFactory.class.getClassLoader(). getResource("config.properties").getPath())); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } } private DaoFactory() {} public static DaoFactory getFactory() { return factory; } public UserDao getDao() { try { String cla = prop.getProperty("UserDao");//com.lmd.dao.MysqlUserDao return (UserDao)Class.forName(cla).newInstance(); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } }} 修改UserService: //private XmlUserDao dao = new XmlUserDao(); //private MysqlUserDao dao = new MysqlUserDao(); private UserDao dao = DaoFactory.getFactory().getDao(); 配置文件 config.properties: driver=com.mysql.jdbc.Driverurl=jdbc:mysql://localhost:3306/day10username=rootpassword=666666UserDao=com.lmd.dao.MysqlUserDao#UserDao=com.lmd.dao.XmlUserDao          3、自定义dao异常。        4、SQL注入攻击:定义DAO接口,并定义Dao工厂,实现service层和dao层的解耦。 (1)、由于dao中执行的 SQL语句是拼接出来的,其中有一部分内容是由用户从客户端传入,所以当用户传入的数据中包含sql关键字时,就有可能通过这些关键字改变sql语句的语义,从而执行一些特殊的操作,这样的攻击方式就叫做sql注入攻击。  (登陆之后,注销,再次回来,只有用户名也可以登录) admin 'or' 1=1,密码空,也可以登录成功。 (2)、 PreperedStatement是Statement的孩子,它的实例对象可以通过调用 Connection.preparedStatement() 方法获得,相对于Statement对象而言: 1)、PreperedStatement可以避免SQL注入的问题。 2)、 Statement会使数据库频繁编译SQL,可能造成数据库缓冲区溢出。 PreparedStatement 可对SQL进行预编译,从而提高数据库的执行效率。 3)、 并且PreperedStatement对于sql中的参数,允许使用占位符的形式进行替换, 简化sql语句的编写。 PreparedStatement利用 预编译 的机制将sql语句的主干和参数分别传输给数据库服务器,从而使数据库分辨 的出哪些是sql语句的主干哪些是参数,这样一来即使参数中带了sql的关键字,数据库服务器也仅仅将他当 作参数值使用,关键字不会起作用,从而从原理上防止了sql注入的问题 package com.lmd.jdbc;import java.sql.Connection;import java.sql.ResultSet;import java.sql.PreparedStatement;import com.lmd.util.JDBCUtils;public class JDBCDemo3 { public static void main(String[] args) { Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; try { conn = JDBCUtils.getConn(); //主干语句 ps = conn.prepareStatement("select * from user where name=? and password=?"); ps.setString(1, "lisi"); ps.setString(2, "888888"); rs = ps.executeQuery(); while (rs.next()) { System.out.println(rs.getString("email")); } } catch (Exception e) { e.printStackTrace(); } finally { JDBCUtils.close(rs, ps, conn); } }} (3)、 PreparedStatement主要有如下的三个优点: ~1.可以 防止sql注入 ~2.由于使用了 预编译机制,执行的效率要高于Statement。 ~3.sql语句使用 ?形式替代参数,然后再用方法设置?的值,比起拼接字符串,代码更加优雅。 二、JDBC应用 (一)、使用JDBC处理大数据         1、基础:          (1)、 在实际开发中,程序需要把大文本 Text 或二进制数据 Blob保存到数据库。 Text是mysql叫法,Oracle中叫Clob。          (2)、基本概念:大数据也称之为LOB(Large Objects),LOB又分为: clob和blob                      1)、clob用于存储大文本。Text                           2)、 blob用于存储二进制数据,例如图像、声音、二进制文等。          (3)、对MySQL而言只有blob,而没有clob,mysql存储大文本采用的是Text,Text和blob分别又分为:   1)、Text:TINYTEXT(255)、TEXT(64k)、MEDIUMTEXT(16M)和LONGTEXT(4G)                           2)、 Blob:TINYBLOB、BLOB、MEDIUMBLOB和LONGBLOB         2、使用JDBC处理大文本:          (1)、 对于MySQL中的Text类型,可调用如下方法设置: PreparedStatement.setCharacterStream(index, reader, length);//注意length长度须设置,并且设置为int型//当包过大时修改配置:[mysqld] max_allowed_packet=64M          (2)、对MySQL中的Text类型,可调用如下方法获取: reader = resultSet. getCharacterStream(i);等价于reader = resultSet.getClob(i).getCharacterStream() package com.lmd.job;/* * create table textdemo( * id int primary key auto_increment, * name varchar(20), * content MEDIUMTEXT * ); */import java.io.File/FileReader;import java.sql.Connection/PreparedStatement/ResultSet;import org.junit.Test;import com.lmd.util.JDBCUtils;public class TextDemo1 { @Test public void addText() { Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; try{ conn = JDBCUtils.getConn(); ps = conn.prepareStatement("insert into textdemo values (null, ?,?)"); ps.setString(1, "三生三世十里桃花.txt"); File file = new File("三生三世十里桃花.txt"); ps.setCharacterStream(2, new FileReader(file), file.length()); ps.executeUpdate(); } catch(Exception e){ e.printStackTrace(); } finally { JDBCUtils.close(rs, ps, conn); } }} 修改java虚拟机启动内存大小: 查看安装目录下的myeclipse.ini: #utf8 (do not remove)-startupplugins/org.eclipse.equinox.launcher_1.3.100.v20150511-1540.jar--launcher.libraryplugins/org.eclipse.equinox.launcher.win32.win32.x86_64_1.1.300.v20150602-1417-vmD:\Program Files\MyEclipse2016\binary\com.sun.java.jdk8.win32.x86_64_1.8.0.u66\bin\javaw.exe-configurationD:\Program Files\MyEclipse2016\configuration-installD:\Program Files\MyEclipse2016-vmargs-Xmx1024m-XX:ReservedCodeCacheSize=64m-Dosgi.nls.warnings=ignore 异常处理 1.Exception in thread "main" java.lang.AbstractMethodError: com.mysql.jdbc.PreparedStatement.setCharacterStream(ILjava/io/Reader;J)Vps.setCharacterStream(2, new FileReader(file), file.length()); 第三个参数是long型的是从1.6才开始支持的,驱动里还没有开始支持。 解决方案:ps.setCharacterStream(2, new FileReader(file), (int)file.length());2.Exception in thread "main" java.lang.OutOfMemoryError: Java heap space 文件大小过大,导致PreparedStatement中数据多大占用内存,内存溢出 -Xms256M-Xmx256M3.com.mysql.jdbc.PacketTooBigException: Packet for query is too large (10886466 > 1048576). You can change this value on the server by setting the max_allowed_packet' variable. 数据库连接传输用的包不够大,传输大文本时报此错误 在my.ini中配置max_allowed_packet指定包的大小 1、修改java虚拟机启动内存大小: CMD修改:java -Xms 64M -Xmx 128M MyEclipse中Run-->Run config...-->Arugument-->VMargument: -Xms64m 换行 -Xmx 128m 2、 com.mysql.jdbc.PacketTooBigException: Packet for query is too large (6882307 > 4194304).  You can change this value on the server by setting the max_allowed_packet' variable. 修改C:\ProgramData\MySQL\MySQL Server 5.6下的my.ini:在[msqld]中写 public void findText() { Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; try{ conn = JDBCUtils.getConn(); ps = conn.prepareStatement("select * from textdemo where id=?"); ps.setInt(1,2); rs = ps.executeQuery(); while (rs.next()) { String name = rs.getString("name"); System.out.println(name);//三生三世十里桃花.txt Reader reader = rs.getCharacterStream("content"); Writer writer = new FileWriter(name); char[] chs = new char[1024]; int len = 0; while ((len = reader.read(chs))!=-1) { writer.write(chs, 0, len); } reader.close(); writer.close(); } } catch(Exception e){ e.printStackTrace(); } finally { JDBCUtils.close(rs, ps, conn); } }  3 、使用JDBC处理二进制数据:          (1)、 对于MySQL中的BLOB类型,可调用如下方法设置: PreparedStatement. setBinaryStream(i, inputStream, length);          (2)、对MySQL中的BLOB类型,可调用如下方法获取: InputStream in = resultSet.getBinaryStream(i);InputStream in = resultSet.getBlob(i).getBinaryStream(); @Test public void addBlob() { try{ conn = JDBCUtils.getConn(); ps = conn.prepareStatement("insert into blobdemo values (null,?,?)"); ps.setString(1, "欢迎您.mp3"); File file = new File("1.mp3"); ps.setBinaryStream(2, new FileInputStream(file), file.length()); ps.executeUpdate(); } } @Test public void findBlob() { try{ conn = JDBCUtils.getConn(); ps = conn.prepareStatement("select * from blobdemo where id=?"); ps.setInt(1,1); rs = ps.executeQuery(); while (rs.next()) { String name = rs.getString("name"); System.out.println(name);//欢迎您.mp3 InputStream input = rs.getBinaryStream("content"); OutputStream output = new FileOutputStream(name); byte[] bys = new byte[1024]; int len = 0; while ((len = input.read(bys))!=-1) { output.write(bys, 0, len); } input.close(); output.close(); } } 但是:图片和音乐等一般不会存在数据库中,只需要知道就行。大文件一般放在服务器的硬盘上,访问的是服务器存在的 文件的硬盘路径,通过读路径得到大文件。  3 、使用JDBC进行批处理:          (1)、业务场景:当需要向数据库发送一批SQL语句执行时,应避免向数据库一条条的发送执行,而应采用JDBC的 批处理机制,以提升执行效率。          (2)、 实现批处理有两种方式,第一种方式:                      1)、void   Statement.addBatch(sql)  。                      2)、 执行批处理SQL语句。                       3)、int[]   executeBatch()方法:执行批处理命令。返回包含批中每个命令的一个元素的更新计数所组成的数组。                       4)、void  clearBatch()方法:清除批处理命令 。               采用Statement.addBatch(sql)方式实现批处理:                  优点:可以向数据库发送多条不同的SQL语句。                   缺点SQL语句没有预编译。 当向数据库发送多条语句相同,但仅参数不同的SQL语句时,需重复写上很多条SQL语句。 package com.lmd.batch;import java.sql.Connection;import java.sql.ResultSet;import java.sql.Statement;import com.lmd.util.JDBCUtils;public class StatementBatch { public static void main(String[] args) { Connection conn = null; Statement stat = null; try { conn = JDBCUtils.getConn(); stat = conn.createStatement(); stat.addBatch("create database day10batch"); stat.addBatch("use day10batch"); stat.addBatch("create table batchdemo(" +"id int primary key auto_increment," + "name varchar(20))"); stat.addBatch("insert into batchdemo values(null,'aaa')"); stat.addBatch("insert into batchdemo values(null,'bbb')"); stat.addBatch("insert into batchdemo values(null,'ccc')"); stat.addBatch("insert into batchdemo values(null,'ddd')"); stat.executeBatch();//返回int类型的数组 } catch (Exception e) { e.printStackTrace(); } finally { JDBCUtils.close(null, stat, conn); } }} 结果如下: mysql> use day10batch;Database changedmysql> select * from batchdemo;+----+------+| id | name |+----+------+| 1 | aaa || 2 | bbb || 3 | ccc || 4 | ddd |+----+------+4 rows in setmysql>           (3)、 实现批处理有两种方式,第一种方式: PreparedStatement.addBatch()                采用PreparedStatement.addBatch()实现批处理,将一组参数添加到此 PreparedStatement 对象的批处理命令中。                    优点:发送的是预编译后的SQL语句,执行效率高。                    缺点:只能应用在SQL语句相同,但参数不同的批处理中。因此此种形式的批处理经常用于在同一个表中批量插入数据,或批量更新表的数据。 package com.lmd.batch;import java.sql.Connection;import java.sql.PreparedStatement;import com.lmd.util.JDBCUtils;/*create table psbatch( id int primary key auto_increment, name varchar(20)); */public class PreparedStatementBatch { public static void main(String[] args) { Connection conn = null; PreparedStatement ps = null; try { conn = JDBCUtils.getConn(); ps = conn.prepareStatement("insert into psbatch values(null,?)"); for (int i = 0; i < 100001; i++) { ps.setString(1, "name"+i); ps.addBatch(); if (i%1000==0) { ps.executeBatch(); ps.clearBatch(); } } ps.executeBatch();//为了剩下的那一条记录 } catch (Exception e) { e.printStackTrace(); } finally { JDBCUtils.close(null, ps, conn); } }} 结果如下: mysql> select count(*) from psbatch;+----------+| count(*) |+----------+| 419 |+----------+1 row in setmysql> select count(*) from psbatch;+----------+| count(*) |+----------+| 689 |+----------+1 row in setmysql>

转载于:https://www.cnblogs.com/angel11288/p/28ea9cd81e4e2665d1a778f7e14e16d5.html

最新回复(0)