使用JDBC连接MySQL数据库的一个基本案例
JDBC的概念(摘自百度百科)
JDBC(Java DataBase Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序。
将Java语言和JDBC结合起来使程序员不必为不同的平台编写不同的应用程序,只须写一遍程序就可以让它在任何平台上运行,这也是Java语言“编写一次,处处运行”的优势。
JDBC对Java程序员而言是API,对实现与数据库连接的服务提供商而言是接口模型。作为API,JDBC为程序开发提供标准的接口,并为数据库厂商及第三方中间件厂商实现与数据库的连接提供了标准方法。
简单地说,JDBC 可做三件事:与数据库建立连接、发送 操作数据库的语句并处理结果。
JDBC的相关架构
jdbc的作用位置:
jdbcAPI:
jdbc相关URL:
JDBC的构建步骤:
注意:
1)测试数据程序之前,一定要记得打开数据库所在计算机的mySQL服务。不然浪费的时间不可限量。
2)一定记得导入mySQL的jar包。
3)最好将Connection对象设置成单例模式,以防止数据库访问量过大时,造成内存崩溃。
4)使用Class对象的forName()方法,要在静态方法中或者静态块中。
5)记得相关数据库操作后进行释放内存,清理环境。
6)PreparedStatement继承自Statement,所以Statement的相关方法,PreparedStatement可以调用。同时PreparedStatement很强大,推荐多使用它。
7)要将相关释放内存的语句放在try...catch语句中的finally中,以防止try块中的语句执行失败而相关内存没有得到释放。
展示案例
package com.java_JDBC; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class JDBC_test { private static String Driver="com.mysql.jdbc.Driver"; //数据库驱动 //连接数据库的URL地址 private static String url="jdbc:mysql://localhost:3306/hellojdbc?useUnicode=true&characterEncoding=UTF-8"; private static String username="root";//数据库连接用户名 private static String password="123456";//数据库连接密码 private static Connection conn=null;//数据库连接对象 private static Statement stat=null;//语句陈述对象 private static ResultSet rs=null;//结果数据集 private static PreparedStatement pst=null;//预编译语句 //使用静态块的方式加载驱动 static { try { //调用Class对象的静态forName()方法加载数据库驱动类 Class.forName(Driver); } catch (ClassNotFoundException e) { e.printStackTrace(); } } //使用单例模式返回数据库连接对象 public static Connection getConnection() throws SQLException{ if(conn==null){ conn=DriverManager.getConnection(url, username, password); return conn; } return conn; } //测试数据库连接是否正常 public static void isConnect() throws SQLException{ Connection con=getConnection(); if(con!=null) System.out.println("数据库连接正常"); else System.out.println("数据库连接失败"); } //查询全部数据库表中所有信息 public static void QueryToAll(){ try { stat=conn.createStatement();//由连接获取语句陈述对象 rs=stat.executeQuery("select * from roster");//获取结果集信息 while(rs.next()){ System.out.println("id:"+rs.getInt("id")+",name:"+rs.getString("name")+",age:"+rs.getInt("age")); } } catch (SQLException e) { e.printStackTrace(); }finally{ clean(); } } //按名字查找数据库中信息 public static void QueryForName(String name){ try { pst = conn.prepareStatement("select * from roster where name=?");//获取预编译语句 pst.setString(1, name);//设置预编译语句参数 rs=pst.executeQuery();//执行预编译语句,获取结果数据集 while(rs.next()){ System.out.println("id:"+rs.getInt("id")+",name:"+rs.getString("name")+",age:"+rs.getInt("age")); } } catch (SQLException e) { e.printStackTrace(); }finally{ clean(); } } //增加数据库中数据信息 public static void insert(){ try { String sql="insert into roster(id,name,age) values ('4','zhangsan','14')"; stat=conn.createStatement(); int count=stat.executeUpdate(sql);//执行语句陈述对象的更新操作 System.out.println("插入操作成功,插入信息条数为"+count); } catch (SQLException e) { e.printStackTrace(); }finally{ clean(); } } //修改数据库中数据信息 public static void alter(){ try { String sql="update roster set age=12 where name='zhangsan'"; stat=conn.createStatement(); int count = stat.executeUpdate(sql);//执行语句陈述对象的更新操作 System.out.println("修改操作成功,修改信息条数为"+count); } catch (SQLException e) { e.printStackTrace(); }finally{ clean(); } } //删除数据库中数据信息 public static void delete(){ try { String sql="delete from roster where name='zhangsan'"; stat=conn.createStatement(); int count=stat.executeUpdate(sql);//执行语句陈述对象的更新操作 System.out.println("删除操作成功,删除信息条数为"+count); } catch (SQLException e) { e.printStackTrace(); }finally{ clean(); } } //释放内存,清理环境 public static void clean(){ try { if(rs!=null) rs.close(); if(pst!=null) pst.close(); if(stat!=null) stat.close(); //不能关闭单例模式下的connection连接对象,否则当一个数据库操作完成后便不能进行其他数据库操作 // if(conn!=null) // conn.close(); // } catch (SQLException e) { e.printStackTrace(); } } public static void main(String[] args) throws SQLException { isConnect(); QueryForName("Bob"); System.out.println("--------------------------------------"); QueryToAll(); System.out.println("--------------------------------------"); insert(); System.out.println("--------------------------------------"); QueryToAll(); System.out.println("--------------------------------------"); alter(); System.out.println("--------------------------------------"); QueryToAll(); System.out.println("--------------------------------------"); delete(); System.out.println("--------------------------------------"); QueryToAll(); } }
执行结果:
使用JDBC常遇到的问题:
问题一:
编写sql语言的过滤条件太弱,导致一次读出过多的数据记录。
解决方法:修改或增加过滤条件。
问题二:
海量数据读取,可能造成溢出异常。(数据条数过多)
分析原因:读出的数据量超过了JVM的内存限制。
解决方法:使用“游标”。每次只读出来一部分数据记录进行处理,处理完成以后再对下一部分数据记录进行读取处理。
如何使用“游标”?
1)首先需要在数据库的URL中增加一个参数:
相关代码示例:
import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public class JDBC_fetch { private static String Driver="com.mysql.jdbc.Driver"; private static String url="jdbc:mysql://localhost:3306/hellojdbc?useCursorFetch=true"; private static String username="root";//数据库连接用户名 private static String password="123456";//数据库连接密码 private static PreparedStatement pst=null; private static ResultSet rs=null; private static Connection conn=null; static { try { Class.forName(Driver); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static void fetchTest(){ try { conn=DriverManager.getConnection(url, username, password); pst=conn.prepareStatement("select * from roster"); pst.setFetchSize(1);//设置游标大小 rs=pst.executeQuery(); while(rs.next()){ System.out.println("id:"+rs.getInt("id")+",name:"+rs.getString("name")+",age:"+rs.getInt("age")); } } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static void main(String[] args) { fetchTest(); }
如上面游标大小设置,JDBC就会一次读取一条记录,处理完再读取下一条记录。
在本案例中输出效果和不设置游标的结果是相同的。
问题三:
读取数据库表大字段,例如博客,图片等等。(单个数据量所占内存过大)
解决方法:
使用流方式。将数据以流的方式,每次读取一段。
相关代码实例:
while(rs.next()){ //获取对象流 InputStream in=rs.getBinaryStream("blog"); //将对象流写入文件 File f=new File(FILE_URL); OutputStream out=null; out=new FileOutStream(f); int temp=0; while((temp=in.read())!=-1) out.write(temp);//边读边写 } in.close(); out.close();
问题四:
海量数据插入数据库,一条一条地插入————太慢
分析原因:每一条数据的插入都需要客户端到服务器的交互,每一次都存在时间消耗和代价。
解决方法:
批处理。一次提交多条sql语句,节省网络开销。
怎么进行批处理?
相关代码示例:
//批处理 Statement stmt=conn.createStatement(); for(String user:users){ stmt.addBatch("insert into roster(name) values("+user+")"); } stmt.executeBatch(); stmt.clearBatch();
问题五:
中文乱码的问题。
解决方法:
在数据库URL中加入“characterEncoding=UTF-8”
private static String url="jdbc:mysql://localhost:3306/hellojdbc?useUnicode=true&characterEncoding=UTF-8";
参考博客: