Java学习-JDBC练习
JDBC总结
1.导入驱动包、加载具体驱动: Class.forName("具体的驱动类 比如 com.mysql.jdbc.Driver ");
2.与数据库建立连接:Connection c = DriverManager.getConnection("......")
3.通过connection,获取操作数据库的对象【statement、preparedStatement【更推荐】、callableStatement】:Statement s=c.createStatement();
4.处理结果集【ResultSet rs = s.getResultSet()】【while(rs.next()){ rs.getXXX(...)}】
基本异常:【 Class.forName抛出:ClassNotFoundException】【其余的都抛出:SQLException】
5.关闭顺序【finally{ 打开顺序与关闭顺序相反:先打开的 后关闭;后打开的 先关闭 }】
【关闭前先确定是否为空,排除空指针异常】【if( !=null ){ 关闭xxx }】
练习1
借助循环,向数据库中插入100条数据,并在mysql-front中观察查询结果
1 package jdbc; 2 3 import java.sql.Connection; 4 import java.sql.DriverManager; 5 import java.sql.SQLException; 6 import java.sql.Statement; 7 8 public class TestJDBC { 9 public static void main(String[] args) { 10 // 初始化驱动 11 try { 12 Class.forName("com.mysql.jdbc.Driver"); 13 } catch (ClassNotFoundException e) { 14 // TODO Auto-generated catch block 15 e.printStackTrace(); 16 } 17 // 使用try-with-resource的方式自动关闭连接,因为Connection和Statement都实现了AutoCloseable接口 18 try ( 19 Connection c = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8", 20 "root", "admin"); 21 Statement s = c.createStatement();) { 22 s.execute("truncate table hero"); 23 String name = null; 24 float hp = 100.0f; 25 int damage = 100; 26 for (int i = 0; i < 100; i++) { 27 name = "\'" + "Hero-" + String.valueOf(i + 1) + "\'"; //注意格式,必须单引号' 28 String sql = "insert into hero values(null," + name + "," + (hp++) + "," + (damage++) + ")"; 29 s.execute(sql); 30 } 31 } catch (SQLException e) { 32 // TODO Auto-generated catch block 33 e.printStackTrace(); 34 } 35 36 } 37 }
效果图:
练习二
向数据库中插入100条数据,比较传统方式和数据库连接池方式的性能差异
1. 使用传统方式创建100个线程,每个线程都会创建新的连接,通过这个连接向数据库插入1条数据,然后关闭这个连接。
2. 使用数据库连接池的方式,创建一个有10条连接的连接池,然后创建100个线程,每个线程都会向连接池借用连接,借用到后,向数据库插入1条数据,然后归还这个连接。
通过时间统计,比较这两种方式的性能表现差异。
1 package jdbc; 2 3 import java.sql.Connection; 4 import java.sql.DriverManager; 5 import java.sql.SQLException; 6 import java.sql.PreparedStatement; 7 import java.util.ArrayList; 8 import java.util.List; 9 10 /* 11 * 向数据库中插入100条数据,比较传统方式和数据库连接池方式的性能差异 12 13 1. 使用传统方式创建100个线程,每个线程都会创建新的连接,通过这个连接向数据库插入1条数据,然后关闭这个连接。 14 15 2. 使用数据库连接池的方式,创建一个有10条连接的连接池,然后创建100个线程,每个线程都会向连接池借用连接,借用到后,向数据库插入1条数据,然后归还这个连接。 16 17 通过时间统计,比较这两种方式的性能表现差异。 18 */ 19 public class Test6 { 20 public static void traditionalWay() { 21 List<Thread> list = new ArrayList<>(); 22 for (int i = 0; i < 100; i++) { 23 Thread t = new Thread() { 24 public void run() { 25 // 初始化驱动 26 try { 27 Class.forName("com.mysql.jdbc.Driver"); 28 } catch (ClassNotFoundException e) { 29 e.printStackTrace(); 30 } 31 // 建立连接 32 try (Connection c = DriverManager.getConnection( 33 "jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8", "root", "admin");){ 34 String sql = "insert into hero values(null,?,?,?)"; 35 PreparedStatement ps = c.prepareStatement(sql); 36 ps.setString(1, "Hero-traditional" ); 37 ps.setFloat(2, 500f); 38 ps.setInt(3, 200); 39 ps.execute(); 40 } catch (SQLException e) { 41 // TODO Auto-generated catch block 42 e.printStackTrace(); 43 } 44 45 } 46 }; 47 // t.start(); //不知为何在for循环里开始多线程总是出错(too many connections),改为在下面统一开始多线程就没问题 48 list.add(t); 49 } 50 for (Thread x : list) { 51 try { 52 x.start(); //统一开始多线程 53 x.join(); 54 } catch (InterruptedException e) { 55 // TODO Auto-generated catch block 56 e.printStackTrace(); 57 } 58 } 59 60 } 61 62 63 public static void ConnectionPoolWay() { 64 List<Thread> list = new ArrayList<>(); 65 ConnectionPool cp = new ConnectionPool(10); 66 for (int i = 0; i < 100; i++) { 67 Thread t = new Thread() { 68 public void run() { 69 Connection c = cp.getConnection(); 70 String sql = "insert into hero values(null,?,?,?)"; 71 try (PreparedStatement ps = c.prepareStatement(sql)) { 72 ps.setString(1, "Hero-ConnectionPool"); 73 ps.setFloat(2, 500f); 74 ps.setInt(3, 200); 75 ps.execute(); 76 } catch (SQLException e) { 77 // TODO Auto-generated catch block 78 e.printStackTrace(); 79 } 80 cp.returnConnection(c); 81 } 82 }; 83 t.start(); 84 list.add(t); 85 } 86 for (Thread x : list) { 87 try { 88 x.join(); 89 } catch (InterruptedException e) { 90 // TODO Auto-generated catch block 91 e.printStackTrace(); 92 } 93 } 94 } 95 96 97 public static class ConnectionPool { 98 List<Connection> cs = new ArrayList<>(); 99 int size; 100 101 public ConnectionPool(int size) { //连接池大小 102 this.size = size; 103 init(); 104 } 105 public void init() { 106 107 // 这里恰恰不能使用try-with-resource的方式,因为这些连接都需要是"活"的,不要被自动关闭了 108 try { 109 Class.forName("com.mysql.jdbc.Driver"); 110 for (int i = 0; i < size; i++) { 111 Connection c = DriverManager.getConnection( 112 "jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8", "root", "admin"); 113 cs.add(c); 114 115 } 116 } catch (ClassNotFoundException e) { 117 // TODO Auto-generated catch block 118 e.printStackTrace(); 119 } catch (SQLException e) { 120 // TODO Auto-generated catch block 121 e.printStackTrace(); 122 } 123 } 124 125 public synchronized Connection getConnection() { 126 while (cs.isEmpty()) { 127 try { 128 this.wait(); 129 } catch (InterruptedException e) { 130 // TODO Auto-generated catch block 131 e.printStackTrace(); 132 } 133 } 134 Connection c = cs.remove(0); 135 return c; 136 } 137 138 public synchronized void returnConnection(Connection c) { 139 cs.add(c); 140 this.notifyAll(); 141 } 142 } 143 public static void main(String[] args) { 144 145 146 long s1 = System.currentTimeMillis(); 147 traditionalWay(); 148 long e1 = System.currentTimeMillis(); 149 150 long s2 = System.currentTimeMillis(); 151 ConnectionPoolWay(); 152 long e2= System.currentTimeMillis(); 153 154 System.out.println("传统方式下,耗时"+(e1-s1)+" ms"); 155 System.out.println("连接池方式下,耗时"+(e2-s2)+" ms"); 156 } 157 }
效果图:
练习3
1 import java.io.File; 2 import java.io.FileInputStream; 3 import java.io.FileNotFoundException; 4 import java.io.FileWriter; 5 import java.io.IOException; 6 import java.io.InputStream; 7 import java.io.InputStreamReader; 8 import java.io.Reader; 9 import java.io.UnsupportedEncodingException; 10 import java.sql.Connection; 11 import java.sql.DriverManager; 12 import java.sql.SQLException; 13 14 import java.sql.PreparedStatement; 15 import java.sql.ResultSet; 16 17 public class JDBC_CLOB_Demo { 18 // 连接字符串:数据库名:IP端口 定位数据库所在计算机的位置 19 // 通过用户名密码 访问具体的数据库 20 private static final String URL = "jdbc:oracle:thin:@localhost:1521:ORCL"; 21 private static final String USERNAME = "scott"; 22 private static final String PWD = "tiger"; 23 24 // 存放小说 25 public static void demo() throws IOException { 26 // 需要mynovel表:create table mynovel(id number primary key,novel clob); 27 // 怎么创建CLOB对象? 28 // 推荐使用setCharacterStream() 29 PreparedStatement pstmt = null; 30 try { 31 Class.forName("oracle.jdbc.OracleDriver"); 32 } catch (ClassNotFoundException e) { 33 // TODO Auto-generated catch block 34 e.printStackTrace(); 35 } 36 37 try (Connection connection = DriverManager.getConnection(URL, USERNAME, PWD);) { 38 String sql = "insert into mynovel values(?,?)"; 39 pstmt = connection.prepareStatement(sql); 40 pstmt.setInt(1, 1); 41 42 // new InputReader()不推荐,不能设置编码 43 // 推荐使用InputStreamReader(inputStream,编码)【转换流】,可以设置编码 44 // 一句代码搞定 45 // pstmt.setCharacterStream(2, 46 // new InputStreamReader(new FileInputStream("F:\\世界名著\\追忆似水年华_马赛尔·普鲁斯特_TXT小说天堂.txt"), "UTF-8")); 47 // 拆分成多行代码便于分析 48 File file = new File("F:\\世界名著\\追忆似水年华_马赛尔·普鲁斯特_TXT小说天堂.txt"); 49 InputStream in = new FileInputStream(file); 50 Reader reader = new InputStreamReader(in, "UTF-8"); 51 // 设置file.length()是为了把整本小说都放进去,所以前面也要设置File对象,方便调用length() 52 // 放入数据库中的是Reader对象,到时候读取时也是取出Reader对象 53 pstmt.setCharacterStream(2, reader, file.length()); 54 // pstmt.setCharacterStream(2, reader, (int)file.length());有可能要转成int才不会报错 55 56 int count = pstmt.executeUpdate(); 57 if (count > 0) 58 System.out.println("操作成功!"); 59 // 记得关闭流操作 60 reader.close(); 61 } catch (SQLException e) { 62 // TODO Auto-generated catch block 63 e.printStackTrace(); 64 } 65 66 } 67 68 // 读取小说 69 public static void readDemo() throws IOException { 70 PreparedStatement pstmt = null; 71 ResultSet rs = null; 72 try { 73 Class.forName("oracle.jdbc.OracleDriver"); 74 } catch (ClassNotFoundException e) { 75 // TODO Auto-generated catch block 76 e.printStackTrace(); 77 } 78 79 try (Connection connection = DriverManager.getConnection(URL, USERNAME, PWD);) { 80 String sql = "select novel from mynovel where id=?"; 81 pstmt = connection.prepareStatement(sql); 82 // 取id=1的小说 83 pstmt.setInt(1, 1); 84 // 开始读取 85 rs = pstmt.executeQuery(); 86 // 就查询 一本小说,不用while 87 if (rs.next()) { 88 // 从数据库取出小说,放在内存的reader对象中 89 Reader reader = rs.getCharacterStream("novel"); 90 // reader与writer对应,用writer输出即可,这里输出到项目的src目录下 91 FileWriter writer = new FileWriter("src/小说.txt"); 92 93 // 设置缓冲区chs,形成:内存---缓冲区---硬盘的输出路径 94 char[] chs = new char[100]; 95 int len = -1; 96 while ((len = reader.read(chs)) != -1) { 97 writer.write(chs,0, len); 98 } 99 writer.close(); 100 reader.close(); 101 } 102 } catch (SQLException e) { 103 // TODO Auto-generated catch block 104 e.printStackTrace(); 105 } 106 } 107 108 public static void main(String[] args) throws IOException { 109 // demo(); 110 readDemo(); 111 } 112 }
直接通过数据库是不能查看整本小说的~
测试成功!
从数据库读取小说 测试成功!
1 import java.io.File; 2 import java.io.FileInputStream; 3 import java.io.FileNotFoundException; 4 import java.io.FileOutputStream; 5 import java.io.FileWriter; 6 import java.io.IOException; 7 import java.io.InputStream; 8 import java.io.InputStreamReader; 9 import java.io.OutputStream; 10 import java.io.OutputStreamWriter; 11 import java.io.Reader; 12 import java.io.UnsupportedEncodingException; 13 import java.sql.Connection; 14 import java.sql.DriverManager; 15 import java.sql.SQLException; 16 17 import java.sql.PreparedStatement; 18 import java.sql.ResultSet; 19 20 public class JDBC_BLOB_Demo { 21 // 连接字符串:数据库名:IP端口 定位数据库所在计算机的位置 22 // 通过用户名密码 访问具体的数据库 23 private static final String URL = "jdbc:oracle:thin:@localhost:1521:ORCL"; 24 private static final String USERNAME = "scott"; 25 private static final String PWD = "tiger"; 26 27 // 在数据库中存放二进制类型 28 public static void demo() throws IOException { 29 PreparedStatement pstmt = null; 30 try { 31 Class.forName("oracle.jdbc.OracleDriver"); 32 } catch (ClassNotFoundException e) { 33 // TODO Auto-generated catch block 34 e.printStackTrace(); 35 } 36 37 try (Connection connection = DriverManager.getConnection(URL, USERNAME, PWD);) { 38 String sql = "insert into mymusic values(?,?)"; 39 pstmt = connection.prepareStatement(sql); 40 pstmt.setInt(1, 1); 41 42 File file = new File("C:\\Users\\Administrator\\Downloads\\Compressed\\Music\\滨崎步My All.mp3"); 43 InputStream in = new FileInputStream(file); 44 pstmt.setBinaryStream(2, in, (int) file.length()); 45 46 int count = pstmt.executeUpdate(); 47 if (count > 0) 48 System.out.println("操作成功!"); 49 // 关闭流 50 in.close(); 51 } catch (SQLException e) { 52 // TODO Auto-generated catch block 53 e.printStackTrace(); 54 } 55 56 } 57 58 // 读取数据库中的二进制数据 59 public static void readDemo() throws IOException { 60 PreparedStatement pstmt = null; 61 ResultSet rs = null; 62 try { 63 Class.forName("oracle.jdbc.OracleDriver"); 64 } catch (ClassNotFoundException e) { 65 // TODO Auto-generated catch block 66 e.printStackTrace(); 67 } 68 69 try (Connection connection = DriverManager.getConnection(URL, USERNAME, PWD);) { 70 String sql = "select music from mymusic where id=?"; 71 pstmt = connection.prepareStatement(sql); 72 pstmt.setInt(1, 1); 73 74 rs = pstmt.executeQuery(); 75 76 if (rs.next()) { 77 78 // 读取数据库中的二进制数据,放在内存的InputStream对象 79 InputStream in = rs.getBinaryStream("music"); 80 81 OutputStream out = new FileOutputStream("src/music.mp3"); 82 83 // 设置缓冲区chs,形成:内存->in.read->缓冲区->out.write->硬盘 84 byte[] chs = new byte[100]; 85 int len = -1; 86 while ((len = in.read(chs)) != -1) { 87 out.write(chs, 0, len); 88 } 89 out.close(); 90 in.close(); 91 } 92 } catch (SQLException e) { 93 // TODO Auto-generated catch block 94 e.printStackTrace(); 95 } 96 } 97 98 public static void main(String[] args) throws IOException { 99 // demo(); 100 readDemo(); 101 } 102 }
测试成功!