数据库中JDBC重点总结

JDBC是Java数据库连接技术的简称,提供连接各种常用数据库的能力。

 

JDBC API:

  1. 实现Java程序对各种数据库的访问
  2. 一组接口和类,位于java. sql与javax. sqI包
  3. 面向接口编程

学习方法:

  1. JDBC步骤固定,理解记忆
  2. 多练习,加深理解

JDBC访问数据库步骤:

DriverManager:依据数据库的不同,管理JDBC驱动

Connection:负责连接数据库并担任传送数据的任务 

Statement:由 Connection 产生、负责执行SQL语句

ResultSet:负责保存Statement执行后所产生的查询结果

 

通过JDBC连接数据库:

操作步骤:

  1. Class. forName(String)加载驱动
  2. 获得数据库连接(Connection)
  3. 创建Statement或PreparedStatement对象、执行sql语句
  4. 返回并处理执行结果(若查询操作,返回ResultSet)
  5. 释放资源

 

JDBC驱动由数据库厂商提供:

在个人开发与测试中,可以使用JDBC-ODBC桥连方式

在生产型开发中,推荐使用纯Java驱动方式

使用JDBC-ODBC桥方式连接数据库:

  1. 将对JDBC API的调用,转换为对另一组数据库连接API的调用
  2. 优点:可以访问所有ODBC可以访问的数据库
  3. 缺点:执行效率低、功能不够强大

使用JDBC-ODBC进行桥连:

  1. 配置数据源:控制面板 ---> ODBC数据源 ---> 系统DNS
  2. 编程获取连接

示例:

使用纯Java方式连接数据库:

  1. 由JDBC驱动直接访问数据库
  2. 优点:完全Java代码,快速、跨平台
  3. 缺点:访问不同的数据库需要下载专用的JDBC驱动

示例:

 

JDBC编程模板:

 

使用JDBC操作数据库--增删改查:

Statement常用方法:

方法名

说    明

ResultSet executeQuery(String sql)

执行SQL查询并获取到ResultSet对象

int executeUpdate(String sql)

可以执行插入、删除、更新等操作,返回值是执行该操作所影响的行数

boolean execute(String sql)

可以执行任意SQL语句,然后获得一个布尔值,表示是否返回ResultSet

 

ResultSet常用方法:

方法名

说    明

boolean next()

将游标从当前位置向下移动一行

boolean previous()

游标从当前位置向上移动一行

void close()

关闭ResultSet 对象

int getInt(int colIndex)

以int形式获取结果集当前行指定列号值

int getInt(String colLabel)

以int形式获取结果集当前行指定列名值

float getFloat(int colIndex)

以float形式获取结果集当前行指定列号值

float getFloat(String colLabel)

以float形式获取结果集当前行指定列名值

String getString(int colIndex)

以String 形式获取结果集当前行指定列号值

String getString(String colLabel)

以String形式获取结果集当前行指定列名值

 

示例:(使用statement进行查询)

//查询新闻id、标题和摘要

public static void main(String[] args) {

       Connection connection=null;

       Statement stmt=null;

       ResultSet rs =null;

       try {

              //加载不同的数据库厂商提供的驱动

              //Class.forName()的意思是根据字符串来找到这个驱动和以前写的Driver d = new Driver();一样    ,就是创建了一个Driver的驱动化示例

              Class.forName("com.mysql.jdbc.Driver");

              //铺路(获取连接Connection)

              String url="jdbc:mysql://127.0.0.1:3306/kgcnews";

              //连接每一个数据库的URL是固定的一搜就可以了

              //把Driver驱动的这个实例放到DriverManager这个应用管理器里,使用驱动的getConnection()方法,;来获得数据库连接

              connection = DriverManager.getConnection(url,"root", "08170327");

              //(2)下圣旨(sql命令)

              String sql = "SELECT id,title FROM news_detail";

              //(3)找一个小太监帮皇上执行圣旨(statement/PreparedStatement)

              stmt = connection.createStatement();

              //(4)拉回西瓜(返回结果集resultSet)

              rs = stmt.executeQuery(sql);

              while(rs.next()){

//int id = rs.getInt(1);

//String title = rs.getString(2);

                     int id = rs.getInt("id");

                     String title = rs.getString("title");

                     System.out.println(id+"\t"+title);

              }

       } catch (ClassNotFoundException e) {

              e.printStackTrace();

       } catch (SQLException e) {

              e.printStackTrace();

       }finally{

              //(5)关闭城门(释放资源)

              try {

                     rs.close();

                     stmt.close();

                     connection.close();

              } catch (SQLException e) {

                     e.printStackTrace();

              }  }  }

 

Statement与PreparedStatement区别:

1. PreparedStatement接口继承Statement

2. Statement st = connection. createStatement () ;

3. PreparedStatement pstm = connection. prepareStatement (sql) ;

a. SQL语句使用“?”作为数据占位符

b. 使用setXxx()方法设置数据

c. executeQuery()括号里面不填东西

4. PreparedStatement--预编译

Statement会把SQL语句发给数据库管理系统DBMS,检查语法,然后编译,然后执行

而PreparedStatement就会先把SQL语句检查编译完了,再在发给DBMS执行

5. PreparedStatement效率更高、性能更好、开销更小、安全性更高、代码可读性更好

 

示例:(使用PreparedStatement进行增删改查)

//使用JDBC实现课工场新闻数据的增删改查

public class NewsDao3 {

       Connection connection=null;

       PreparedStatement ptmt=null;

       ResultSet rs =null;

       //提取重复的代码,减少冗余

       //获取数据库连接

       public void getConnection(){

              //加载不同的数据库厂商提供的驱动

              //Class.forName()的意思是根据字符串来找到这个驱动和以前写的Driver d = new Driver();一样    ,就是创建了一个Driver的驱动化示例

              try {

                     Class.forName("com.mysql.jdbc.Driver");

                     //铺路(获取连接Connection)

                     String url="jdbc:mysql://127.0.0.1:3306/kgcnews";

                     //连接每一个数据库的URL是固定的一搜就可以了

                     //把Driver驱动的这个实例放到DriverManager这个应用管理器里,使用驱动的getConnection()方法,;来获得数据库连接

                     connection = DriverManager.getConnection(url,"root", "08170327");

              } catch (ClassNotFoundException e) {

                     e.printStackTrace();

              } catch (SQLException e) {

                     e.printStackTrace();

              }     

       }

              //增加新闻信息的方法

       public void addNews(int id,int categoryid,String title,String summary,String content,String author,Date createdate){

              this.getConnection();

              try{

                     String sql = "INSERT INTO news_detail(id,categoryid,title,summary,content,author,createdate) VALUES(?,?,?,?,?,?,?)";

                     ptmt = connection.prepareStatement(sql);

                     ptmt.setInt(1,id);

                     ptmt.setInt(2,categoryid);

                     ptmt.setString(3,title);

                     ptmt.setString(4,summary);

                     ptmt.setString(5,content);

                     ptmt.setString(6,author);

                     ptmt.setTimestamp(7,new Timestamp(createdate.getTime()));

                     //增删改都用executeUpdate()

                     int i = ptmt.executeUpdate();

                     if(i>0){

                            System.out.println("插入新闻成功!");

                     }

              } catch (SQLException e) {

                     e.printStackTrace();

              }finally{

                     try {

                            ptmt.close();

                            connection.close();

                     } catch (SQLException e) {

                            e.printStackTrace();

                     }  }  }

       //删除特定新闻的方法

       public void deleteNews(int id){

              this.getConnection();

              try{

                     String sql = "DELETE FROM news_detail WHERE id=?";

                     ptmt = connection.prepareStatement(sql);

                     ptmt.setInt(1,id);

                     int i = ptmt.executeUpdate(); //增删改都用executeUpdate()

                     if(i>0){

                            System.out.println("删除新闻成功!");

                     }

              } catch (SQLException e) {

                     e.printStackTrace();

              }finally{

                     try {

                            ptmt.close();

                            connection.close();

                     } catch (SQLException e) {

                            e.printStackTrace();

                     }  }  }

       //修改特定新闻标题的方法

       public void updateNews(int id,String title){

              this.getConnection();

              try{

                     String sql = "UPDATE news_detail SET title =? WHERE id=?";

                     ptmt = connection.prepareStatement(sql);

                     ptmt.setString(1,title);

                     ptmt.setInt(2,id);

                     int i = ptmt.executeUpdate(); //增删改都用executeUpdate()

                     if(i>0){

                            System.out.println("修改新闻成功!");

                     }

              } catch (SQLException e) {

                     e.printStackTrace();

              }finally{

                     try {

                            ptmt.close();

                            connection.close();

                     } catch (SQLException e) {

                            e.printStackTrace();

                     }  }  }

       //查询全部新闻信息

       public void getNewsList(){

              this.getConnection();

              try {

                     this.getConnection();

                     String sql = "SELECT id,categoryid,title,summary,content,author,createdate FROM news_detail";

                     ptmt = connection.prepareStatement(sql);

                     rs = ptmt.executeQuery();

                     while(rs.next()){

                            int id = rs.getInt("id");

                            int categoryid = rs.getInt("categoryid");

                            String newsTitle = rs.getString("title");

                            String summary = rs.getString("summary");

                            String content = rs.getString("content");

                            String author = rs.getString("author");

                            Timestamp createdate = rs.getTimestamp("createdate");

System.out.println(id+"\t"+categoryid+"\t"+newsTitle+"\t"+summary+"\t"+content+"\t"+author+"\t"+createdate);

                     }

              } catch (SQLException e) {

                     e.printStackTrace();

              }finally{

                     try {

                            ptmt.close();

                            connection.close();

                     } catch (SQLException e) {

                            e.printStackTrace();

                     }  }  }

       //查询特定标题的新闻信息

       public void getNewsByTitle(String title){

              try {

                     this.getConnection();

                     //(2)下圣旨(sql命令)

                     //使用PreparedStatement就不用拼字符串了

                     //拼字符串容易出错

                     //拼字符串可读性太差

                     //使用?,?是占位符具体想传谁,?就是谁

                     String sql = "SELECT id,title FROM news_detail where title=?";

                     //(3)找一个小太监帮皇上执行圣旨(statement/PreparedStatement)

                     ptmt = connection.prepareStatement(sql);

                     //在SQL语句的第一个问号的位置填充title

                     ptmt.setString(1,title);

                     //System.out.println(sql);

                     //(4)拉回西瓜(返回结果集resultSet)

                     rs = ptmt.executeQuery();

                     while(rs.next()){

//int id = rs.getInt(1);

//String title = rs.getString(2);

                            int id = rs.getInt("id");

                            String newsTitle = rs.getString("title");

                            System.out.println(id+"\t"+newsTitle);

                     }

              } catch (SQLException e) {

                     e.printStackTrace();

              }finally{

                     //(5)关闭城门(释放资源)

                     try {

                            rs.close();

                            ptmt.close();

                            connection.close();

                     } catch (SQLException e) {

                            e.printStackTrace();

                     }  }  }

       public static void main(String[] args) {

              NewsDao3 dao2 = new NewsDao3();

              //dao2.getNewsByTitle("Java Web开课啦");

              //dao2.getNewsByTitle("Java Web开课啦");

              //如果语句是:"Java Web开课啦' or '1'='1"

              //就会拼成SELECT id,title FROM news_detail where title='Java Web开课啦' or '1'='1'

              //只要有一个true就会把全部信息查出来,这个叫做SQL漏洞

              //dao2.addNews(4, 1, "test", "test", "test", "maoxin", new Date());

              //dao2.deleteNews(2);

              //dao2.updateNews(3, "newTitle");

              //dao2.getNewsList();

       }      }

 

Class.forName("")     【后加载】

后加载是一开始不知道创建哪个类对象,运行的时候给一个字符串,根据这个字符串找到他对应的类,然后才加载到Java虚拟机中去,然后再创建类和对象,这个叫做反射

反射机制就是指事先不知道任何信息,在Java运行期间,才知道要去使用哪个类,如何去创建,获取类的相关信息(包括创建类和对象,包括获得这个类的方法,包括获得类的属性)

 

Student s = new Student();   【先加载】

先加载是预先知道类型之后直接加载到Java虚拟机,先有这个信息然后根据这个信息创建对象,先把Student加载到Java虚拟机然后才能new:JVM ---> Student

 

数据库操作优化思路:

  1. 提取数据库公共操作(获取数据库连接、释放资源、增删改、查)形成一个数据库操作的基类
  2. 将NewsDao提取一个稳定的新闻操作的接口

 

编写完增删改查的方法的弊端:

  1. 将相似功能的代码抽取封装成方法,减少代码冗余
  2. 因为不同的数据库会有不同的实现,对数据库的操作一般抽取成接口,在以后的开发中可以降低耦合
  3. 数据库发生改变时,要重新修改代码,重新编译和部署:

将数据库信息写在配置文件当中,让程序通过读取配置文件来获得这些信息

配置文件:属性文件   .properties (都是键值对的形式);

 

为了解决弊端要进行封装,封装的方案:

1. 隔离业务逻辑代码和数据访问代码

2. 隔离不同数据库的实现

 

3. 让用户脱离程序本身修改相关的变量设置——使用配置文件

Java中的配置文件常为properties文件

  1. 后缀为.properties
  2. 格式是“键=值”格式
  3. 使用“#”来注释

示例:

jdbc.driver=com.mysql.jdbc.Driver

jdbc.connection.url=jdbc:mysql://127.0.0.1:3306/kgcnews

jdbc.connection.username=root

jdbc.connection.password=08170327

Java中提供了Properties类来读取配置文件:

方法名

说明

String getProperty(String key)

用指定的键在此属性列表中搜索属性。通过参数key得到其所对应的值

Object setProperty(String key,String value)

调用Hashtable的方法put。通过调用基类的put()方法来设置键-值对

void load(InputStream inStream)

从输入流中读取属性列表 (键和元素对)。通过对指定文件进行装载获取该文件中所有键-值对

void clear()

清除所装载的键-值对,该方法由基类Hashtable提供

使用配置文件的方法:

a. 读取数据库属性文件,获取数据库连接信息

b. 使用静态方法:

①使用了静态之后就直接ConfigManager.getInstance().getString("jdbc.driver");就可以了

②提供给别人一个唯一的ConfigManager对象,如果不存在就new一个,如果存在就直接return

③使用静态的方法,不定义成static的话,用户只能new一个对象,但是已经定义成了私有方法,所以不能new;只能定义成静态方法,好处就是不用new对象直接类名就行

private static ConfigManager configManager;

c. 单例模式(让用户只能创建一个ConfigManager):

ConfigManager对象在内存里只有一个示例,不能重复new,只要构造一次就可以

①使用单例模式的时候:先改成私有的就不能随便new了

private ConfigManager()

②把程序提供给别人唯一对象

d. 获取文件名:

String configFile = "database.properties";

e. 使用文件流输出文件中的内容:

①InputStream是一个文件流;把database.properties这个文件通过ConfigManager里的类加载器getClassLoader()里的getResourceAsStream()方法就可以把一个资源变成一个流

②这个方法就可以把配置文件读到输入流里面去,这个方法找配置文件会在根目录下找文件,所以配置文件一定要写在src的根目录下

InputStream in = ConfigManager.class.getClassLoader().getResourceAsStream(configFile);

f. 把数据流加进来

通过properties的load方法把输入流加载进来

properties.load(in);

g. 根据键取出值

通过getProperty()方法就可以根据属性文件中的键获得对应的值

properties.getProperty(key);

 

示例:

public class ConfigManager {

private static ConfigManager configManager;

private Properties properties;

private ConfigManager(){

String configFile = "database.properties";

InputStream in = ConfigManager.class.getClassLoader().getResourceAsStream(configFile);

properties = new Properties();

try {

properties.load(in);

in.close();

} catch (IOException e) {

e.printStackTrace();

}   }

public static synchronized ConfigManager getInstance(){

        if(configManager == null){

               configManager=new ConfigManager();

        }

        return configManager;

}

public String getString(String key){

return properties.getProperty(key);

}   }

 

单例模式有两种实现方式:

1. 饿汉方式:

不管调不调用都new出来这个对象,new对象的时机是只要加载这个类到虚拟机里就会加载静态方法new一个对象,此时不管调不调用getInstance()

饿汉方式不存在线程安全的问题

示例:

public class ConfigManager {

private static ConfigManager configManager = new ConfigManager;

private Properties properties;

private ConfigManager(){

String configFile = "database.properties";

InputStream in = ConfigManager.class.getClassLoader().getResourceAsStream(configFile);

try {

properties.load(in);

in.close();

} catch (IOException e) {

e.printStackTrace();

}   }

public static ConfigManager getInstance(){

return configManager;

}

public String getString(String key){

return properties.getProperty(key);

}   }

 

2. 懒汉方式:

  1. 当需要用这个方法的时候,再去new这个对象,并且保证就new一个
  2. 懒汉方式的缺点是线程不安全,如果两个人同时调用,就会有可能内存里还是出现了多个configManager对象
  3. 解决方法是把方法改成public static synchronized ConfigManager getInstance()
  4. synchronized的意思是同步,意思是上了一个锁,第一个人完全执行之后,第二个人才能进入,这就避免了线程不安全

示例:

最开始的就是这个例子

 

4. 使用实体类传递数据

数据访问代码和业务逻辑代码之间通过实体类来传输数据

实体类特征:

  1. 属性一般使用private修饰
  2. 提供public修饰的getter/setter方法
  3. 实体类提供无参构造方法,根据业务提供有参构造
  4. 实现java.io.Serializable接口,支持序列化机制

 

总结:

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值