JDBC是J2SE的内容,是由java提供的访问数据库的接口,但没有提供具体的实现方法,需要数据库厂商提供,就是对应的数据库驱动。
这样的好处是可以方便的更换数据库,提高了扩展性。这也是面向接口编程的一个优点。
1 import java.sql.Connection; 2 import java.sql.DriverManager; 3 import java.sql.ResultSet; 4 import java.sql.SQLException; 5 import java.sql.Statement; 6 7 public class Demo { 8 public static void main(String[] args) throws ClassNotFoundException, SQLException{ 9 //连接数据库,获取连接对象 10 Connection conn=connection(); 11 //使用连接对象进行数据库的操作:增、删、改 12 sqlDemo(conn); 13 //使用连接对象进行数据库的操作:查 14 queryDemo(conn); 15 //sql规范写法, 16 sqlDemo2(); 17 } 18 19 public static Connection connection() throws ClassNotFoundException, SQLException { 20 21 /*注册数据库驱动对象的简便方法: 22 * Java中在使用数据库对象时,需要通过相应的驱动来实现,并且要通过DriverManager类来注册这个驱动 23 * 上面的操作已经被写入驱动类中的静态代码块中了,所以可以直接加载该类就实现了上述操作 24 * 25 * 在jdbc4.0之后的版本中有些数据库驱动有一个配置文件可以进行注册,也就是可以省略下面一句, 26 * 但是并非所有驱动都可以,而且为了兼容性更好,建议使用 27 */ 28 Class.forName("com.mysql.jdbc.Driver"); 29 30 //获取数据库连接对象 31 /*jdbc四大配置参数 32 * driverClassName(与使用的数据库对应):com.mysql.jdbc.Driver 33 * url:(Java连接数据库的地址,非http协议的url)jdbc:mysql://localhost:3306/库名 34 * user:数据库用户名 35 * password:数据库密码 36 */ 37 String url="jdbc:mysql://localhost:3306/test"; 38 String user="root"; 39 String password="920346"; 40 Connection _conn=DriverManager.getConnection(url, user, password); 41 return _conn; 42 } 43 44 public static void sqlDemo(Connection conn) throws SQLException { 45 /*发送sql语句需要使用Statement对象,语句是正常的sql语句,注意不要加;结束 46 * 增删改语句的发送使用executeUpdate();返回受影响行数 47 */ 48 Statement stat=conn.createStatement(); 49 String sql="INSERT INTO test1 VALUES(2,3)"; 50 int l=stat.executeUpdate(sql); 51 sql="UPDATE test1 SET num1=2 WHERE num1=1"; 52 l=stat.executeUpdate(sql); 53 sql="DELETE FROM test1 WHERE num1=2"; 54 l=stat.executeUpdate(sql); 55 System.out.println(l); 56 } 57 58 private static void queryDemo(Connection conn) throws SQLException { 59 /*查询语句和上面的增删改的不同在于返回值: 60 * 1、查询返回结果集;其他返回影响行数 61 * 2、查询使用的是executeQuery();其他使用executeUpdate() 62 */ 63 /*在创建语句发送器对象时,就已经决定了获取的结果集对象的特性,可以通过参数进行设置 64 * 默认只能向下移动,即执行next() 65 */ 66 Statement stat=conn.createStatement(); 67 String sql="SELECT * FROM test1"; 68 /*查询得到的结果集对象就是对数据表的抽象,是一张表,有行有列,对结果集的操作就是对行和列的操作 69 * 对行的操作就是定位、移动和获取行数 --》结果集光标 70 * 对列的操作就是获取列的信息(列数/类型),获取列的值 --》元数据 71 */ 72 ResultSet rs=stat.executeQuery(sql); 73 while(rs.next()){ 74 int num1=rs.getInt("num1"); 75 int num2=rs.getInt(2); 76 System.out.println("num1="+num1+",num2="+num2); 77 } 78 79 //数据库连接也是一种资源,使用之后必须关闭,而且上面的三个对象都要关闭 80 rs.close(); 81 stat.close(); 82 conn.close(); 83 } 84 85 //sql代码书写规范:包括异常处理 86 public static void sqlDemo2(){ 87 Connection conn=null; 88 Statement stat=null; 89 try{ 90 conn=connection(); 91 stat=conn.createStatement(); 92 String sql="INSERT INTO test1 VALUES(2,3)"; 93 int l=stat.executeUpdate(sql); 94 sql="UPDATE test1 SET num1=2 WHERE num1=1"; 95 l=stat.executeUpdate(sql); 96 sql="DELETE FROM test1 WHERE num1=2"; 97 l=stat.executeUpdate(sql); 98 System.out.println(l); 99 }catch(Exception e){ 100 throw new RuntimeException(); 101 }finally{ 102 //防止空指针异常 103 try{ 104 if(stat!=null) 105 stat.close(); 106 if(conn!=null) 107 conn.close(); 108 }catch(SQLException e){ 109 throw new RuntimeException(); 110 } 111 } 112 } 113 }
上面的查询使用的是Statement对象,但是有一个缺点就是可能存在Sql攻击德尔问题,可以使用PreapredStatement对象最为替代,
1 import java.io.IOException; 2 import java.sql.Connection; 3 import java.sql.DriverManager; 4 import java.sql.PreparedStatement; 5 import java.sql.ResultSet; 6 import java.sql.SQLException; 7 import java.sql.Statement; 8 9 import org.junit.Test; 10 11 12 /** 13 * PreapredStatement的使用: 14 * 防SQL攻击 15 * @author cxf 16 * 17 */ 18 public class Demo2 { 19 /** 20 * 登录 21 * 使用username和password去查询数据 22 * 若查出结果集,说明正确!返回true 23 * 若查出不出结果,说明用户名或密码错误,返回false 24 * @param username 25 * @param password 26 * @return 27 * @throws Exception 28 */ 29 public boolean login(String username, String password) throws Exception { 30 /* 31 * 一、得到Connection 32 * 二、得到Statement 33 * 三、得到ResultSet 34 * 四、rs.next()返回的是什么,我们就返回什么 35 */ 36 // 准备四大参数 37 String driverClassName = "com.mysql.jdbc.Driver"; 38 String url = "jdbc:mysql://localhost:3306/test"; 39 String mysqlUsername = "root"; 40 String mysqlPassword = "920346"; 41 // 加载驱动类 42 Class.forName(driverClassName); 43 // 得到Connection 44 Connection con = DriverManager.getConnection(url, mysqlUsername, mysqlPassword); 45 46 // 得到Statement 47 Statement stmt = con.createStatement(); 48 49 // 给出sql语句,调用stmt的executeQuery(),得到ResultSet 50 String sql = "select * from j_stu where username='" + username + "' and password='" + password + "'"; 51 System.out.println(sql); 52 ResultSet rs = stmt.executeQuery(sql); 53 54 return rs.next(); 55 } 56 57 /** 58 * SQL攻击! 59 * @throws Exception 60 */ 61 @Test 62 public void fun1() throws Exception { 63 //select * from t_user where username='a' or 'a'='a' and password='a' or 'a'='a' 64 String username = "a' or 'a'='a"; 65 String password = "a' or 'a'='a"; 66 boolean bool = login(username, password); 67 System.out.println(bool); 68 } 69 70 public boolean login2(String username, String password) throws Exception { 71 /* 72 * 一、得到Connection 73 * 二、得到Statement 74 * 三、得到ResultSet 75 * 四、rs.next()返回的是什么,我们就返回什么 76 */ 77 // 准备四大参数 78 String driverClassName = "com.mysql.jdbc.Driver"; 79 String url = "jdbc:mysql://localhost:3306/test?useServerPrepStmts=true&cachePrepStmts=true"; 80 String mysqlUsername = "root"; 81 String mysqlPassword = "920346"; 82 // 加载驱动类 83 Class.forName(driverClassName); 84 // 得到Connection 85 Connection con = DriverManager.getConnection(url, mysqlUsername, mysqlPassword); 86 87 /////////////////////////////////////// 88 /////////////////////////////////////// 89 90 91 /* 92 * 一、得到PreparedStatement 93 * 1. 给出sql模板:所有的参数使用?来替代 94 * 2. 调用Connection方法,得到PreparedStatement 95 */ 96 String sql = "select * from j_stu where username=? and password=?"; 97 PreparedStatement pstmt = con.prepareStatement(sql); 98 99 /* 100 * 二、为参数赋值 101 */ 102 pstmt.setString(1, username);//给第1个问号赋值,值为username 103 pstmt.setString(2, password);//给第2个问号赋值,值为password 104 105 ResultSet rs = pstmt.executeQuery();//调用查询方法,向数据库发送查询语句 106 107 //重复使用赋值,需要关闭上次的结果流,并清空原设置 108 rs.close(); 109 pstmt.clearParameters(); 110 111 pstmt.setString(1, "liSi"); 112 pstmt.setString(2, "123"); 113 rs = pstmt.executeQuery();//调用查询方法,向数据库发送查询语句 114 115 return rs.next(); 116 } 117 118 @Test 119 public void fun2() throws Exception { 120 //select * from t_user where username='a' or 'a'='a' and password='a' or 'a'='a' 121 String username = "zhangSan"; 122 String password = "123"; 123 boolean bool = login2(username, password); 124 System.out.println(bool); 125 } 126 127 /** 128 * 测试JdbcUtils.getConnection() 129 * @throws SQLException 130 * @throws ClassNotFoundException 131 * @throws IOException 132 */ 133 @Test 134 public void fun3() throws SQLException { 135 Connection con = JdbcUtils.getConnection(); 136 System.out.println(con); 137 Connection con1 = JdbcUtils.getConnection(); 138 System.out.println(con1); 139 } 140 }
1 import java.sql.Connection; 2 import java.sql.SQLException; 3 4 import org.junit.Test; 5 6 public class Demo5 { 7 /*jdbc中使用事务的演示:转账 8 * !!!事务是由连接对象管理,所以事务过程必须使用同一个连接对象 9 */ 10 public void transfers(String from,String to,Double money){ 11 Connection conn=null; 12 try{ 13 conn=JdbcUtils.getConnection(); 14 //开启事务 15 conn.setAutoCommit(false); 16 //执行事务内容 17 AccountDao dao=new AccountDao(); 18 dao.updateBalance(conn,from, -money); 19 dao.updateBalance(conn,to, money); 20 //提交事务 21 conn.commit(); 22 conn.close(); 23 }catch(Exception e){ 24 try { 25 conn.rollback(); 26 conn.close(); 27 } catch (SQLException e1) { 28 throw new RuntimeException(e); 29 } 30 } 31 } 32 @Test 33 public void fun1(){ 34 transfers("zs","lisi",100.00); 35 } 36 }
从上面的基础代码可以看出有三个对象非常重要:Connection,Statement/PreparedStatement,ResultSet.还有就是注册驱动有多种方式,上面使用的是推荐用法。
以上就是JDBC的基本使用,但是也存在一些问题,
①数据库连接使用完之后需要释放,如果经常需要连接影响性能。
②数据库的使用代码有很多都是重复的,例如获取Connection对象,异常处理等。
③对查询结果集Result对象的处理
针对上面问题的解决方案:
①使用连接池代替原始的数据库连接,连接池就是一种装饰者模式,对连接对象的close()进行增强。
1 import java.beans.PropertyVetoException; 2 import java.sql.Connection; 3 import java.sql.SQLException; 4 5 import org.apache.commons.dbcp.BasicDataSource; 6 import org.junit.Test; 7 8 import com.mchange.v2.c3p0.ComboPooledDataSource; 9 10 public class Demo6 { 11 /*使用数据库连接池获取连接对象,连接池的配置还可以在配置文件中作为资源进行配置,称为JNDI, 12 * 1、DBCP连接池 13 * 2、C3P0连接池 14 */ 15 @Test 16 public void fun1() throws SQLException{ 17 //数据库连接池是装饰者模式,是对Connection对象进行增强, 18 //获取连接池对象 19 BasicDataSource dataSource=new BasicDataSource(); 20 //配置连接参数,因为连接池也要依靠四大参数连接数据库,并且也需要使用数据库驱动 21 dataSource.setDriverClassName("com.mysql.jdbc.Driver"); 22 dataSource.setUrl("jdbc:mysql://localhost:3306/test"); 23 dataSource.setUsername("root"); 24 dataSource.setPassword("920346"); 25 //配置池参数:有默认值, 26 dataSource.setMaxActive(20); //最大活动连接数 27 dataSource.setMaxIdle(3); //最大空闲连接数 28 29 //获取连接对象 30 Connection conn=dataSource.getConnection(); 31 System.out.println(conn.getClass().getName()); 32 33 //注意这里的close()被增强,不是关闭连接,而是将连接对象归还连接池 34 conn.close(); 35 } 36 37 @Test 38 public void fun2() throws SQLException, PropertyVetoException{ 39 //获取连接池对象,和上面操作相似,只是名字有所不同 40 ComboPooledDataSource dataSource=new ComboPooledDataSource(); 41 42 //注意方法名和上面不同 43 dataSource.setDriverClass("com.mysql.jdbc.Driver"); 44 dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test"); 45 dataSource.setUser("root"); 46 dataSource.setPassword("920346"); 47 48 //配置池参数:有默认值, 49 dataSource.setAcquireIncrement(5); 50 dataSource.setInitialPoolSize(20); 51 52 //获取连接对象 53 Connection conn=dataSource.getConnection(); 54 System.out.println(conn.getClass().getName()); 55 56 //注意这里的close()被增强,不是关闭连接,而是将连接对象归还连接池 57 conn.close(); 58 } 59 @Test 60 public void fun3() throws SQLException{ 61 /*c3p0连接池的配置参数可以直接写在配置文件中, 62 * 只要将配置文件保存在类路径下即可在创建类时自动寻找 63 * 注意:默认情况下使用的是默认配置,如果在代码中在进行配置就会将配置文件中的覆盖 64 */ 65 ComboPooledDataSource dataSource=new ComboPooledDataSource(); 66 67 Connection conn=dataSource.getConnection(); 68 System.out.println(conn.getClass().getName()); 69 70 conn.close(); 71 } 72 public void fun4() throws SQLException{ 73 //在配置文件中可以有多个配置,如果不使用默认配置二使用其他配置,只要将节点名作为参数传入即可 74 ComboPooledDataSource dataSource=new ComboPooledDataSource("oracle-config"); 75 76 Connection conn=dataSource.getConnection(); 77 System.out.println(conn.getClass().getName()); 78 79 conn.close(); 80 } 81 }
②使用Apache Commons dbUtils包进行处理
③使用Apache Commons dbUtils包将结果集与java中的对象,集合等结构进行操作
对Apache Commons dbUtils包的说明参见
http://www.jb51.net/article/61886.htm