Jdbc数据库连接(1)

JDBC概述

1 什么是JDBC

  JDBCJava DataBase Connectivity)就是Java数据库连接,说白了就是用Java语言来操作数据库。原来我们操作数据库是在控制台使用SQL语句来操作数据库,JDBC是用Java语言向数据库发送SQL语句。

 

 

2 JDBC原理

早期SUN公司的天才们想编写一套可以连接天下所有数据库的API,但是当他们刚刚开始时就发现这是不可完成的任务,因为各个厂商的数据库服务器差异太大了。后来SUN开始与数据库厂商们讨论,最终得出的结论是,由SUN提供一套访问数据库的规范(就是一组接口),并提供连接数据库的协议标准,然后各个数据库厂商会遵循SUN的规范提供一套访问自己公司的数据库服务器的API出现。SUN提供的规范命名为JDBC,而各个厂商提供的,遵循了JDBC规范的,可以访问自己数据库的API被称之为驱动!

 

JDBC是接口,而JDBC驱动才是接口的实现,没有驱动无法完成数据库连接!每个数据库厂商都有自己的驱动,用来连接自己公司的数据库。

当然还有第三方公司专门为某一数据库提供驱动,这样的驱动往往不是开源免费的!

1  引入数据库的驱动jar包:

Oracleojdbc14-10.2.0.2.0.jar

Mysql:  mysql-connector-java-5.1.13-bin.jar;

需要jar下载,博主我是好人直接上百度网盘:链接:链接: https://pan.baidu.com/s/1YMlbKVqs4KU7tuEnkNZeiA 密码: euny

2. 获取连接

获取连接需要两步,一是使用DriverManager来注册驱动,二是使用DriverManager来获取Connection对象。

  • 注册驱动

看清楚了,注册驱动就只有一句话:Class.forName(“oracle.jdbc.OracleDriver”)

 

  • 获取连接

获取连接的也只有一句代码:DriverManager.getConnection(url,username,password),其中usernamepassword是登录数据库的用户名和密码。

url查对复杂一点,它是用来找到要连接数据库“网址”,就好比你要浏览器中查找百度时,也需要提供一个url。下面是mysqlurl

jdbc:oracle:thin:@127.0.0.1:1521:orcl

JDBC规定url的格式由三部分组成,每个部分中间使用冒号分隔。

第一部分是jdbc,这是固定的;

第二部分是数据库名称,那么连接mysql数据库,第二部分当然是mysql了;

第三部分是由数据库厂商规定的,我们需要了解每个数据库厂商的要求,mysql的第三部分分别由数据库服务器的IP地址(localhost)、端口号(3306),以及DATABASE名称(mydb1)组成。

  

下面是获取连接的语句:

Connection con = DriverManager.getConnection(“jdbc:oracle:thin:@127.0.0.1:1521:orcl

”,”username”,”password”);

3 获取Statement

在得到Connectoin之后,说明已经与数据库连接上了,下面是通过Connection获取Statement对象的代码:

Statement stmt = con.createStatement();

Statement是用来向数据库发送要执行的SQL语句的!

4 发送SQL增、删、改、查语句

String sql = “insert into user value(’zhangSan’, ’123’)”;

int m = stmt.executeUpdate(sql);

其中int类型的返回值表示执行这条SQL语句所影响的行数,我们知道,对insert来说,最后只能影响一行,而updatedelete可能会影响0~n行。

如果SQL语句执行失败,那么executeUpdate()会抛出一个SQLException

发送SQL查询语句

String sql = “select * from user”;

ResultSet rs = stmt.executeQuery(sql);

请注册,执行查询使用的不是executeUpdate()方法,而是executeQuery()方法。executeQuery()方法返回的是ResultSetResultSet封装了查询结果,我们称之为结果集。

5 如果是查询读取结果集中的数据

ResultSet就是一张二维的表格,它内部有一个“行光标”,光标默认的位置在“第一行上方”,我们可以调用rs对象的next()方法把“行光标”向下移动一行,当第一次调用next()方法时,“行光标”就到了第一行记录的位置,这时就可以使用ResultSet提供的getXXX(int col)方法来获取指定列的数据了:

rs.next();//光标移动到下一行

rs.getInt(1);//获取第一行第一列的数据

当你使用rs.getInt(1)方法时,你必须可以肯定第1列的数据类型就是int类型,如果你不能肯定,那么最好使用rs.getObject(1)。在ResultSet类中提供了一系列的getXXX()方法,比较常用的方法有:

Object getObject(int col)

String getString(int col)

int getInt(int col)

double getDouble(int col)

6 关闭资源

IO流一样,使用后的东西都需要关闭!关闭的顺序是先得到的后关闭,后得到的先

关闭。

rs.close();

stmt.close();

con.close(); 

6 示例和步奏说明:

 

 

 相信大家连上面的实例感受到jdbc是干嘛的吧,可能你们会懵比这些类和接口具体是干嘛和怎么用的,下面就来了解了解他们,

3,JDBC接口、类介绍

1 JDBC中的主要类(接口)

JDBC中常用的类有:

lDriverManager –类,用来获取Connection获得数据库的连接

lConnection –接口;

lStatement –接口;

lResultSet –接口。 结果返回



DriverManager--->Connection--->Statement --发送sql-->数据库

2 DriverManager

其实我们今后只需要会用DriverManagergetConnection()方法即可:

1.Class.forName(“oracle.jdbc.OracleDriver”);//注册驱动

2.String url = “jdbc:oracle:thin:@127.0.0.1:1521:orcl”;

3.String username = “scott”;用户名

4.String password = “tiger”;用户密码

5.Connection con = DriverManager.getConnection(url, username, password);

注意,上面代码可能出现的两种异常:

1.ClassNotFoundException:这个异常是在第1句上出现的,出现这个异常有两个可能:

l你没有给出oraclejar包;

l你把类名称打错了,查看类名是不是oracle.jdbc.OracleDriver

2.SQLException:这个异常出现在第5句,出现这个异常就是三个参数的问题,往往usernamepassword一般不是出错,所以需要认真查看url是否打错。

对于DriverManager.registerDriver()方法了解即可,因为我们今后注册驱动只会Class.forName(),而不会使用这个方法。

3 Connection

Connection最为重要的方法就是获取Statement

lStatement stmt = con.createStatement();

后面在学习ResultSet方法时,还要学习一下下面的方法:

lStatement stmt = con.createStatement(int,int);

4 Statement

Statement最为重要的方法是:

lint executeUpdate(String sql):执行更新操作,即执行insertupdatedelete语句,其实这个方法也可以执行create tablealter table,以及drop table等语句,但我们很少会使用JDBC来执行这些语句;

lResultSet executeQuery(String sql):执行查询操作,执行查询操作会返回ResultSet,即结果集。

  boolean execute()

Statement还有一个boolean execute()方法,这个方法可以用来执行增、删、改、查所有SQL语句。该方法返回的是boolean类型,表示SQL语句是否执行成功。

如果使用execute()方法执行的是更新语句,那么还要调用int getUpdateCount()来获取insertupdatedelete语句所影响的行数。

如果使用execute()方法执行的是查询语句,那么还要调用ResultSet getResultSet()来获取select语句的查询结果。

5 ResultSet之获取列数据

可以通过next()方法使ResultSet的游标向下移动,当游标移动到你需要的行时,就需要来获取该行的数据了,ResultSet提供了一系列的获取列数据的方法:

lString getString(int columnIndex):获取指定列的String类型数据;

lint getInt(int columnIndex):获取指定列的int类型数据;

ldouble getDouble(int columnIndex):获取指定列的double类型数据;

lObject getObject(int columnIndex):获取指定列的Object类型的数据。

上面方法中,参数columnIndex表示列的索引,列索引从1开始,而不是0,这第一点与数组不同。如果你清楚当前列的数据类型,那么可以使用getInt()之类的方法来获取,如果你不清楚列的类型,那么你应该使用getObject()方法来获取。

ResultSet还提供了一套通过列名称来获取列数据的方法:

lString getString(String columnName):获取名称为columnName的列的String数据;

lint getInt(String columnName):获取名称为columnName的列的int数据;

ldouble getDouble(String columnName):获取名称为columnName的列的double数据;

lObject getObject(String columnName):获取名称为columnName的列的Object数据;

结果集的列数

ResultSet rs = stm.executeQuery(sql);

ResultSetMetaData rsmd = rs.getMetaData();

intcount = rsmd.getColumnCount();

获取行数 只能通过滚动 resultset

ResultSet rs = stm.executeQuery(sql);

rs.last();

introw = rs.getRow();

 

4 JDBC预编译

 

1 什么是SQL注入

在需要用户输入的地方,用户输入的是SQL语句的片段,最终用户输入的SQL片段与我们DAO中写的SQL语句合成一个完整的SQL语句!例如用户在登录时输入的用户名和密码都是为SQL语句的片段!

 

2 演示SQL注入

 

首先我们需要创建一张用户表,用来存储用户的信息。

 

下面我们写一个login()方法!

 

下面是调用这个方法的代码:

login("a' or 'a'='a", "a' or 'a'='a");

这行当前会使我们登录成功!因为是输入的用户名和密码是SQL语句片段,最终与我们的login()方法中的SQL语句组合在一起!我们来看看组合在一起的SQL语句:

SELECT * FROM tab_user WHERE username='a' or 'a'='a' and password='a' or 'a'='a'

示例代码:

public static void main(String[] args) {

//通过输入不合法的sql片段可以破坏原有的sql带来极大的风险

boolean islogin=login("jie","123'or'a'='a");

System.out.println(islogin);

if(islogin){

System.out.println("登陆成功");

}else{

System.out.println("用户名或密码错误");

}

 

 

}

public static boolean login(String Uname,String pword){

boolean isExsit=false;

 

String driverClass="oracle.jdbc.OracleDriver";

//定义连接oracleurl

String url = "jdbc:oracle:thin:@192.168.42.71:1521:orcl";

//用户名和密码

String uresname = "scott";

//用户密码

String password = "tight";

//定义Connection连接

Connection conn= null;

//定义预编译的sql执行对象

PreparedStatement ps=null;

 

//定义要执行的sql

String querysql="select * from URESS where uresname=? and password=?";

System.out.println(querysql);

//定义查询结果ResultSet对象

ResultSet rs=null;

try {

 

//注册数据库的驱动程序

Class.forName(driverClass);

//获得数据库连接

conn=DriverManager.getConnection(url, uresname, password);

//创建预编译sql执行对象

ps=conn.prepareStatement(querysql);

//给编译好的sql设置参数值,参数值从左到右从1开始

ps.setString(1, Uname);

ps.setString(2, pword);

//执行sql

rs=ps.executeQuery();

//游标是否存在下一条数据

isExsit=rs.next();

 

 

} catch (Exception e) {

e.printStackTrace();

}finally{

try {

//关闭资源

if(ps!=null)

ps.close();

if(rs!=null){

rs.close();

}

if(conn!=null){

conn.close();

}

 

} catch (SQLException e) {

e.printStackTrace();

}

 

}

return isExsit;

 

}

}

 

这样的问题对于我们的系统是相当的不安全的,所以怎么防止sql注入呢,下面介绍一个接口:

3 防止SQL注入

l 过滤用户输入的数据中是否包含非法字符;

使用PreparedStatement

4 PreparedStatement是什么?

PreparedStatement叫预编译声明!

PreparedStatementStatement的子接口,你可以使用PreparedStatement来替换Statement

PreparedStatement的好处:

l防止SQL攻击;

l提高代码的可读性,以可维护性;

l提高效率。

5 PreparedStatement的使用

String sql = “select * from tab_student where s_number=?”;

PreparedStatement pstmt = con.prepareStatement(sql);

pstmt.setString(1, “S_1001”);

ResultSet rs = pstmt.executeQuery();

rs.close();

pstmt.clearParameters();

pstmt.setString(1, “S_1002”);

rs = pstmt.executeQuery();

在使用Connection创建PreparedStatement对象时需要给出一个SQL模板,所谓SQL模板就是有“?SQL语句,其中“?就是参数。

在得到PreparedStatement对象后,调用它的setXXX()方法为“?赋值,这样就可以得到把模板变成一条完整的SQL语句,然后再调用PreparedStatement对象的executeQuery()方法获取ResultSet对象。

注意PreparedStatement对象独有的executeQuery()方法是没有参数的,而StatementexecuteQuery()是需要参数(SQL语句)的。因为在创建PreparedStatement对象时已经让它与一条SQL模板绑定在一起了,所以在调用它的executeQuery()executeUpdate()方法时就不再需要参数了。

PreparedStatement最大的好处就是在于重复使用同一模板,给予其不同的参数来重复的使用它。这才是真正提高效率的原因。

所以,建议大家在今后的开发中,无论什么情况,都去需要PreparedStatement,而不是使用Statement

使用步奏:

第一 定义要执行的sql

String querysql="select * from URESS where uresname=? and password=?";

第二 定义查询结果ResultSet对象

ResultSet rs=null;

第三创建预编译sql执行对象

ps=conn.prepareStatement(querysql);

第四给编译好的sql设置参数值,参数值从左到右从1开始

ps.setString(1, Uname);

ps.setString(2, pword);

第五执行sql

 

rs=ps.executeQuery();

5 JdbcUtils工具类

 

1 JdbcUtils的作用

你也看到了,连接数据库的四大参数是:驱动类、url、用户名,以及密码。这些参数都与特定数据库关联,如果将来想更改数据库,那么就要去修改这四大参数,那么为了不去修改代码,我们写一个JdbcUtils类,让它从配置文件中读取配置参数,然后创建连接对象。

 

2 JdbcUtils代码

JdbcUtils.java

public class JdbcUtils {

private static final String dbconfig = "dbconfig.properties";

private static Properties prop = new Properties();

static {

try {

InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(dbconfig);

prop.load(in);

Class.forName(prop.getProperty("driverClassName"));

} catch(IOException e) {

throw new RuntimeException(e);

}

}

 

public static Connection getConnection() {

try {

return DriverManager.getConnection(prop.getProperty("url"),

prop.getProperty("username"), prop.getProperty("password"));

} catch (Exception e) {

throw new RuntimeException(e);

}

}

}

dbconfig.properties

driverClassName=oracle.jdbc.OracleDriver

url= jdbc:oracle:thin:@127.0.0.1:1521:orcl

username=scott

password=tiger

 

下面介绍下开发模式

1 DAO模式

DAOData Access Object)模式就是写一个类,把访问数据库的代码封装起来。DAO在数据库与业务逻辑(Service)之间。

l实体域(JavaBean),即操作的对象,例如我们操作的表是user表,那么就需要先写一个User类;

lDAO模式需要先提供一个DAO接口;

l然后再提供一个DAO接口的实现类;

l再编写一个DAO工厂,Service通过工厂来获取DAO实现。

 

 

第一步: 把访问数据库的代码封装起来

public class Jdbcutils {

 

  public  static  Connection getConn(){

 InputStream in= Jdbcutils.class.getClassLoader().getResourceAsStream("db.properties");

  Properties prop=new Properties();

  Connection con=null;

  try {

prop.load(in);

String driverClass=prop.getProperty("driverClass");

String url=prop.getProperty("url");

String uresname=prop.getProperty("username");

String password=prop.getProperty("password");

//注册驱动

Class.forName(driverClass);

con=DriverManager.getConnection(url, uresname, password);

 

} catch (Exception e) {

 

e.printStackTrace();

}

return con;

  

  }

  public static PreparedStatement getPstmt(String sql){

  Connection conn=getConn();

  PreparedStatement pstmt=null;

  try {

  pstmt=conn.prepareStatement(sql);

} catch (SQLException e) {

 

e.printStackTrace();

}

return pstmt;

  }

  public static void closeupdateRes(PreparedStatement ps){

  if(ps!=null){

  try {

Connection con=ps.getConnection();

ps.close();

if(con!=null){

con.close();

}

} catch (SQLException e) {

e.printStackTrace();

}

  }

  

  }

  public static  void closeQueryRes(ResultSet rs){

  if(rs!=null){

  Statement st;

try {

st = rs.getStatement();

 if(st !=null){

  Connection con=st.getConnection();

  rs.close();

  st.close();

  if(con!=null){

  con.close();

  }

  }

} catch (SQLException e) {

e.printStackTrace();

}

 

}

  }

}

 

第二步:操作的对象

 

根据表中的属性,创建一个类,属性对应表中的字段

第三步:提供一个DAO接口;

创建一个接口

public interface PersonDao {

 

//添加

public void savePerson(Person p);

 

//修改

public void updatePerson(Person p);

 

//根据id获得对象

public Person getPersonByid(Integer id);

 

//获得所有

public List<Person> listperson();

}

第四步:DAO接口的实现类;

public class PersonDaoImpl implements PersonDao {

 

@Override

public void savePerson(Person p) {

String sql="insert into person values(person_id.nextval,?,?,?)";

PreparedStatement ps=Jdbcutils.getPstmt(sql);

try {

ps.setString(1, p.getName());

ps.executeUpdate();

} catch (Exception e) {

 

e.printStackTrace();

}finally{

Jdbcutils.closeupdateRes(ps);

}

 

}

 

@Override

public void updatePerson(Person p) {

String sql="update person p set p.name=?,p.address=? , p.birhday=? where p.id=?";

PreparedStatement ps=Jdbcutils.getPstmt(sql);

try {

ps.setString(1, p.getName());

ps.setInt(4, p.getId());

ps.executeUpdate();

} catch (Exception e) {

 

e.printStackTrace();

}finally{

Jdbcutils.closeupdateRes(ps);

}

 

}

 

@Override

public Person getPersonByid(Integer id) {

String sql="select * from person p where p.id=?";

PreparedStatement ps=Jdbcutils.getPstmt(sql);

Person p=null;

ResultSet rs=null;

try {

ps.setInt(1, id);

 rs=ps.executeQuery();

//游标下移

rs.next();

 //获得查询出的数据

Integer personid=rs.getInt("id");

String pesonname=rs.getString("name");

String  personaddress =rs.getString("address");

java.util.Date personday=rs.getDate("birhday");

//创建person对象并赋值

    p=new Person();

p.setId(personid);

p.setName(pesonname);

} catch (SQLException e) {

e.printStackTrace();

}finally{

Jdbcutils.closeQueryRes(rs);

}

return p;

}

 

@Override

public List<Person> listperson() {

String sql="select * from person p";

PreparedStatement ps=Jdbcutils.getPstmt(sql);

ResultSet rs=null;

List<Person> plist =new ArrayList<>();

try {

 rs=ps.executeQuery();

//游标下移

 while(rs.next()){

 

 //获得查询出的数据

Integer personid=rs.getInt("id");

String pesonname=rs.getString("name");

String  personaddress =rs.getString("address");

java.util.Date personday=rs.getDate("birhday");

//创建person对象并赋值

   Person p=new Person();

p.setId(personid);

p.setName(pesonname);

plist.add(p);

 }

} catch (SQLException e) {

e.printStackTrace();

}finally{

Jdbcutils.closeQueryRes(rs);

}

return plist;

}

 

}

 

 

 

转载于:https://www.cnblogs.com/mjie/p/9396383.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值