JDBC核心API
Statement
三个方法,分别执行三种语句,DQL,DML,DDL语句。
Statement st = conn.createStatement(); String ddl="create table a "+"(ids varchar(6))"; boolean b=st.execute(ddl); System.out.println(b);
/*这里的返回结果:
TRUE:表示有结果集,
* False:表示没有结果集
* 创建失败抛异常
* 在ddl语句执行如何判断结果,可以根据是否有没有异常,没有则创建成功。
* 在ddl语句中,创建表,实际上没有结果集返回,因为没有二维表返回,在这里并不是创建成功就是TRUE。但是如果执行select查询语句时,就有结果集返回,即为TRUE。*/
这里显示为FALSE,但是实际上是创建成功了。
不仅如此,进行表的删除等操作都是一样的。
注意点:
public class test { public static void main(String[] args) { try{ Class.forName("com.mysql.jdbc.Driver"); String url="jdbc:mysql://127.0.0.1:3306/test"; String username="root"; String password="123456"; Connection conn= DriverManager.getConnection(url,username,password); //创建 Statement Statement st= conn.createStatement(); //执行DML语句 String dml="insert into k (name,id) values('cc',24) "; int b=st.executeUpdate(dml); System.out.println(b); } catch (SQLException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
在idea返回结果
在数据库中查询的结果。
在拼接SQL语句时,一定要注意之间的空格,不然容易报错。
ResultSet
ResultSet代表dql查询结果,是2维结果,其内部维护了一个读取数据的游标,默认情况下,游标在第一行数据之前,当调用next()方法时候,游标会向下移动,并将返回结果集中是否包含数据,如果包含数据就返回TRUE,结果集还提供了很好getXXX方法用于获取结果集游标指向当前行数据。
String sql="select * from k"; ResultSet rs=st.executeQurry(sql); while(rs.next()){ String str=rs.getString("age"), System.out.println(str); }
ResultSetMetaData
ResultSetMetaData:数据结果集的元数据(结果集的相关数据,不是结果集本身)
Connection conn=null; try{ conn=DBUtils.getConnection(); String sql="select * from k"; Statement st=conn.createStatement(); ResultSet rs=conn.executeQuery(sql); //结果集元数据 ResultSetMetaData rsm =rs.getMetaData(); int n=rsm.getColumnCount(); for (int i=1;i<=n;i++){ String name=metaData.getColumnName(i); System.out.println(name); } }catch(Exception e){ e.printStackTrace(); }finally{ DUBtils.close(conn); }
Properties
Properties 读取配置文件
properties 是Java中专门用于读取配置文件的API。
- 其底层就是文本的API
- Propertics 本身实现MAP接口,内部是散列表
- Properties限定key和value都是String类型。
Properties常用的API方法
- load(流) 读取一个配置文件
- String getProperty(key)读取一个属性值
使用步骤:
- 创建properties对象
- 利用load方法读取配置文件
- 利用getproperty查询属性文件内容。
利用配置文件可以将程序中的参数保存到配置文件中,修改程序参数只需要修改配置文件即可。
//1.创建properties 对象 Properties pr=new Properties(); System.out.println(pr); System.out.println(pr.size()); //2.利用load方法读取文件 InputStream in = day02.class.getClassLoader().getResourceAsStream("db.properties"); //执行后,将文件内容读取到了散列表中 pr.load(in); System.out.println(pr); System.out.println(pr.size()); //查找 文件内容,就是读取文件内容 System.out.println(pr.getProperty("jdbc.password"));
# db.properties jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://127.0.0.1:3306/test jdbc.user=root jdbc.password=123456
PreparedStatement
preparedStatement 对象用于执行带参数的预编译执行计划。
//带参数的SQL语句 String sql="insert into k (name,age) values (?,?)"; // 将SQL发送到数据库,创建执行计划,返回值就是代表SQL语句在服务器的执行计划。 PreparedStatement ps=conn.prepareStatement(sql); //替换执行计划中的参数,2个参数,顺序不可错,按照序号发送参数。 ps.setString(1,"bb"); ps.setInt(2,21); //执行执行计划 int n=ps.executeUpdate(); System.out.println(n);
预防SQL
SQL注入的产生
public class login { public static void main(String[] args){ //获取用户输入 Scanner in=new Scanner(System.in); System.out.println("用户名:" ); String name=in.nextLine(); System.out.println("密码:"); String pwd=in.nextLine(); //检查登录情况 boolean pass=login(name,pwd); if (pass){ System.out.println("欢迎你!"+name); }else{ System.out.println("用户名或者密码错误!"); } } //检查用户是否能够登录 public static boolean login(String name,String pwd){ String sql="select * from h where name=\'"+name+"\'"+"and pwd=\'" +pwd+"\' "; System.out.println(sql); Connection conn=null; try { conn=DBUtils.getConnection(); Statement st= conn.createStatement(); ResultSet rs=st.executeQuery(sql); while (rs.next()){ int a=rs.getInt("id"); return a>=1; } }catch (Exception e){ e.printStackTrace(); }finally { DBUtils.close(conn); } return false; } }
SQL注入的原因:
and 的优先级高于or ,所以当前面的FALSE and FALSE,即为 FALSE,但是 or 后面为TRUE,所以FALSE or TRUE,最终结果为TRUE。
用户输入了含有SQL成分的语句的参数,参数在拼接SQL时候造成了SQL语句的语义改变,改变了SQL语句的执行计划!
防守手段:
拦截用户输入的SQL成分。
select * from h where name=? and pwd =?
这种情况,or 只是一个普通的字符串,不当成SQL成分
这种就可以利用preparedStatement。
public class right { public static void main(String[] args){ Scanner in=new Scanner(System.in); System.out.println("用户名:"); String name=in.nextLine(); System.out.println("密码:"); String pwd=in.nextLine(); boolean pass=right(name,pwd); if (pass){ System.out.println("登录成功"); }else { System.out.println("登陆失败"); } } public static boolean right(String name,String pwd){ Connection conn=null; String sql="select * from h "+" where name=? and pwd=? "; System.out.println(sql); try { conn=DBUtils.getConnection(); PreparedStatement pr= conn.prepareStatement(sql); pr.setString(1,name); pr.setString(2,pwd); ResultSet rs=pr.executeQuery(); while (rs.next()){ int n=rs.getInt("id"); return n>=1; } }catch (Exception e){ e.printStackTrace(); }finally { DBUtils.close(conn); } return false; } }
连接管理
在软件中数据库连接使用非常频繁,如果每次都创建连接,就会造成代码的大量冗余,常规做法是建立数据库连接工具类,封装数据库连接流程,统一数据库连接过程,使用时候可以简化代码。
实现步骤:
- 创建数据库连接参数文件,db.properties
- 创建DBUtils.java 封装数据库连接方法
- 利用properties读取配置文件夹中的数据库连接参数
- 创建方法 getConnection方法封装数据库连接过程。
3.使用getConnection()连接数据库
public class DBUtils { static String driver; static String url; static String user; static String password; //静态代码块的目的是从 static { //初始化静态属性 /*1.利用properties读取配置文件 * 2.从配置文件中查找相应参数值 * */ try{ Properties pr=new Properties(); InputSteam in=DBUtils.class.getClassLoader().getResourceAsStream("db.properties"); pr.load(in); System.out.println(pr); //初始化数据 driver=pr.getProperty("jdbc.driver"); url=pr.getProperty("jdbc.url"); password=pr.getProperty("jdbc.password"); user=pr.getProperty("jdbc.user"); in.close(); }catch(IOException e){ e.printStackTrace(); } } /*封装创建数据库连接的过程,简化数据库的连接*/ public static Connection getConnection(){ try { Class.forName(driver); Connection conn=DriverManager.getConnection(url,user,password); return conn; } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } } /* * dbutils.java * 关闭数据库连接方法,封装复杂的关闭过程 * */ public static void close(Connection conn){ if (conn!=null){ try { conn.close(); }catch (Exception e){ e.printStackTrace(); } } } }
这样可以简化重复操作。
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://127.0.0.1:3306/test jdbc.user=root jdbc.password=123456
//创建连接 Connection conn=DBUtils.getConnection(); //创建Statement()对象 Statement st=conn.creataStatement(); String st="select *from k"; //查询结果 ResultSet rs=st.executeQuery(sql); while(rs.next()){ String name=rs.getString("name"); System.out.println("name: "+name); } conn.close();
DriverManager 管理数据库连接适合单线程情况,而在多线程并发情况下,为了能够重用数据库连接,同时控制并发连接总数,保护数据库避免连接重载,一定要使用数据库连接池。
连接池技术
数据库连接池的开源实现非常多,dbcp是常用的连接池之一。
导入dbcp。
导包
从模块中搜索对应的包,然后导入时,点击应用后,在确定。
import org.apache.commons.dbcp2.BasicDataSource; public class day03 { public static void main(String[] args) throws Exception{ String driver="com.mysql.jdbc.Driver"; String url="jdbc:mysql://127.0.0.1:3506/test"; String password="123456"; String user="root"; BasicDataSource ds=new BasicDataSource(); ds.setDriverClassName(driver); ds.setUrl(url); ds.setUsername(user); ds.setPassword(password); //设置连接池的管理参数 ds.setInitialSize(2); ds.setMaxTotal(100); //使用连接池中的数据库连接 Connection conn=ds.getConnection(); //执行SQL String sql="select *from k"; Statement st=conn.createStatement(); ResultSet rs=st.executeQuery(sql); while(rs.next()){ String str=rs.getString("age"); System.out.println(str); } //归还连接到数据库连接池 conn.close(); } }
try{ conn=DBUtils.getConnection(); String sql="select * from k"; Statement st=conn.createStatement(); ResultSet rs=st.executeQuery(sql); while(rs.next()){ String str=rs.getString("name"); System.out.println(str); } rs.close(); st.close(); }
连接并发测试
public class day05 { public static void main(String[] args){ Thread t1=new TestTherad(4000); Thread t2=new TestTherad(5000); Thread t3=new TestTherad(1000); t1.start(); t2.start(); t3.start(); } } class TestTherad extends Thread{ int wait; public TestTherad(int wait){ this.wait=wait; } public void run(){ Connection conn=null; try { conn=DBUtils.getConnection(); System.out.println("获取连接:"+conn); Thread.sleep(wait); String sql="select * from k"; Statement st=conn.createStatement(); ResultSet rs=st.executeQuery(sql); while(rs.next()){ System.out.println(rs.getString("name")); } System.out.println(wait+"结束"); }catch (Exception e){ e.printStackTrace(); }finally { DBUtils.close(conn); } } }