文章目录
- 使用JDBC操作数据库
- 1. JDBC访问数据库步骤
- 2. Statement与PreparedStatement区别
- 3. JDBC的内容
- 4. JDBC封装
- 4.1 为什么进行JDBC封装
- 4.2 实现JDBC封装
- 4.3 什么是DAO
- 4.4 配置数据库访问参数
- 4.5 配置数据库连接池使用之JNDI的方式
- 5. 单例模式
- 5.1 懒汉模式
- 5.2 饿汉模式
使用JDBC操作数据库
JDBC: Java数据库连接技术(Java DataBase Connectivity),能实现Java程序对各种数据库的访问。
由一组使用Java语言编写的类和接口(JDBC API)组成,它们位于java.sql以及javax.sql中。
1. JDBC访问数据库步骤
- Class.forName() 加载驱动
- DriverManager 获取Connection连接
- 创建Statement 执行SQL语句
- 返回ResultSet查询结果
- 释放资源
try {//1.加载驱动Class.forName("com.mysql.cj.jdbc.Driver");//加载数据库路径String url = "jdbc:mysql://127.0.0.1:3306/smbms?useSSL = false";//加载账号String uname = "root";//加载密码String upwd = "1234";//2.DriverManager创建conn对象conn = DriverManager.getConnection(url,uname,upwd);//3.通过Connection创建Statement对象,用于执行SQL语句state = conn.createStatement();//4.准备sql语句String sql = "select id,userCode,userName,userPassword,creationDate from smbms_user where id = 1";//5.使用Statement执行SQL语句,并返回结果rs = state.executeQuery(sql);//6.处理resultSet遍历集合while(rs.next()){user = new User();user.setId(rs.getInt("id"));user.setUserCode(rs.getString("userCode"));user.setUserName(rs.getString("userName"));user.setUserPassword(rs.getString("userPassword"));user.setCreationDate(rs.getDate("creationDate"));}return user;
}catch(Exception e){e.printStackTrace();
}finally {//4.释放资源try {state.close();conn.close();} catch (SQLException e) {e.printStackTrace();}
}
2. Statement与PreparedStatement区别
Statement
由方法createStatement()
创建,该对象用于发送简单的SQL语句PreparedStatement
由方法prepareStatement()
创建,该对象用于发送带有一个或者多个输入参数的SQL语句- SQL语句使用
“?”
作为数据占位符 - 使用
setXxx()
方法设置数据
- SQL语句使用
PreparedStatement
-----预编译
if (getConnection()){String sql = "select * from smbms_user where userCode = ? and userPassword = ?";//预编译sql语句ps = conn.prepareStatement(sql);ps.setString(1,userCode);ps.setString(2,userPassword);rs = ps.executeQuery();while(rs.next()){user = new User();user.setUserName(rs.getString("userName"));user.setUserPassword(rs.getString("userPassword"));}
return user;
3. JDBC的内容
JDBC API
:定义了一系列的接口和类,集成在java.sql和javax.sql包中DriverManager
:管理各种不同的JDBC驱动JDBC
驱动:负责连接不同类型的数据库
优点:
不必为不同的数据库专门编写不同的程序,而只需要加载不同的数据库驱动即可。
4. JDBC封装
4.1 为什么进行JDBC封装
- 将相似功能的代码抽取封装成方法,减少代码冗余
- 因为不同的数据库会有不同的实现,对数据库的操作一般抽取成接口,在以后的开发中可以降低耦合
- 隔离业务逻辑代码和数据访问代码
- 隔离不同数据库的实现
4.2 实现JDBC封装
步骤:
- 将所有增删改查操作抽取成接口
- 定义实体类传输数据
- 将通用的操作(打开、关闭连接等)封装到工具类
- 数据库工具类BaseDao:增、删、改、查的通用方法
package com.company.dao;import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;public class BaseDao {public static String driver;public static String url;public static String uname;public static String upwd;static {//加载流对象Properties properties = new Properties();InputStream is = BaseDao.class.getClassLoader().getResourceAsStream("com/company/dao/jdbc.properties");try {properties.load(is);driver = properties.getProperty("driver");url = properties.getProperty("url");uname = properties.getProperty("uname");upwd = properties.getProperty("upwd");} catch (IOException e) {e.printStackTrace();}}//创建数据库连接public Connection conn = null;public PreparedStatement ps = null;//连接数据库public void getConnection() throws Exception{//加载数据库驱动Class.forName(driver);//定义连接对象conn = DriverManager.getConnection(url,uname,upwd);}//关闭连接public void closeConnection(){try {conn.close();ps.close();} catch (SQLException e) {e.printStackTrace();}}//封装查询public ResultSet selectSql(String sql,Object[] objs) throws SQLException {ResultSet rs = null;if (conn != null) {ps = conn.prepareStatement(sql);for (int i = 0; i < objs.length; i++) {ps.setObject((i+1),objs[i]);}rs = ps.executeQuery();}return rs;}//封装增删改方法(共用)public int sql(String sql,Object[] objs) throws SQLException {int j = 0;if (conn != null){ps = conn.prepareStatement(sql);for (int i = 0;i < objs.length;i++){ps.setObject((i+1),objs[i]);}j = ps.executeUpdate();}return j;}
}
4.3 什么是DAO
Data Access Object(数据存取对象) : 位于业务逻辑和持久化数据之间,实现对持久化数据的访问
DAO起着转换器的作用,将数据在实体类和数据库记录之间进行转换。
DAO模式的组成:
- DAO接口
- DAO实现类
- 实体类
- 数据库连接和关闭工具类
优势:
- 隔离了数据访问代码和业务逻辑代码
- 隔离了不同数据库实现
4.4 配置数据库访问参数
属性文件:
- 后缀为.properties
- 数据格式为“键=值”
- 使用“#”来注释
- Java中提供了Properties类来读取配置文件
mysql.driver = com.mysql.cj.jdbc.Driver
mysql.url = jdbc:mysql://127.0.0.1:3306/smbms?useSSL = false
mysql.uname = root
mysql.upwd = 1234
4.5 配置数据库连接池使用之JNDI的方式
JNDI:
JNDI就是(java Naming and Directory Inteface)java名称目录接口。
JNDI的作用:就是将资源引入到服务器中。可以将JNDI当成一个仓库。将Java对象放入到JNDI中去。
如果我们一开始就有已经创建好了多个connection对象,放在一个公共地方,当有一个连接数据库的请求,就从这个公共地方中取出一个connection,操作数据库,操作完成数据库,不关闭connection,而是放入到公共仓库中去,这就出现了数据库连接池的东西,就是存放多个Connection对象的地方。
使用JNDI配置数据库的连接池:
-
非全局的JNDI配置:
导入要链接数据库的jar包文件。
在JNDI中配置数据库的连接池:在WEB项目中的的META-INF中创建一个context.xml文件。用于设置数据库的连接池信息
<?xml version="1.0" encoding="UTF-8"?> <Context> <!-- 其中Resource标签就是配置资源,他的属性值如下: |- name:表示以后要查找的名称。通过此名称可以找到DataSource,此名称任意更换,但是程序中最终要查找的就是此名称,为了不与其他的名称混淆,所以使用jdbc/oracle,现在配置的是一个jdbc的关于oracle的命名服务。 |- auth:由容器进行授权及管理,指的用户名和密码是否可以在容器上生效,可以使用Container |- type:此名称所代表的类型,现在为javax.sql.DataSource(不用变) |- maxActive:表示一个数据库在此服务器上所能打开的最大连接数 |- maxIdle:表示一个数据库在此服务器上维持的最小连接数 |- maxWait:最大等待时间。10000毫秒 |- username:数据库连接的用户名 |- password:数据库连接的密码 |- driverClassName:数据库连接的驱动程序 |- url:数据库连接的地址 --> <!--配置Oracle数据库的JNDI数据源--> <Resource name="jdbc/oracle"auth="Container" type="javax.sql.DataSource"maxActive="100" maxIdle="30" maxWait="10000"username="lead_oams" password="p"driverClassName="oracle.jdbc.driver.OracleDriver"url="jdbc:oracle:thin:@192.168.1.229:1521:lead"/><!--配置MySQL数据库的JNDI数据源--> <Resource name="jdbc/mysql"auth="Container" type="javax.sql.DataSource"maxActive="100" maxIdle="30" maxWait="10000"username="root" password="root"driverClassName="com.mysql.jdbc.Driver"url="jdbc:mysql://127.0.0.1:3306/smbms?useSSL=false"/><!--配置SQLServer数据库的JNDI数据源--> <Resource name="jdbc/sqlserver"auth="Container" type="javax.sql.DataSource"maxActive="100" maxIdle="30" maxWait="10000"username="sa" password="123456"driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver"url="jdbc:sqlserver://192.168.1.51:1433;DatabaseName=demo"/> </Context>
在web.xml文件中进行配置( 可有可无):如果有的话:
<resource-ref><description>my DB Connection</description><res-ref-name><span style="font-family: Arial, Helvetica, sans-serif;">jdbc/sqlserver</span><span style="font-family: Arial, Helvetica, sans-serif;"></res-ref-name> 这个名字要与context.xml中的name一样</span><res-type>javax.sql.DataSource</res-type><res-auth>Container</res-auth> </resource-ref>
如果使用Spring的情况下:在applicationContext.xml或者自己的Spring的配置文件中:导入JNDI的配置信息
//获得content.xml中JNDI配置的数据库的连接池信息。jndi-name必须与JNDI中的name值一样 <jee:jndi-lookup id="dataSource" jndi-name="jdbc/sqlserver" /> //使用JdbcTemplate操作数据库。 <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSource" /> </bean>
在java文件中使用IOC得到jdbcTemplate对象。最后使用JdbcTemplate操作数据库
如果不使用Spring的话:可以在java文件中使用:
Context initContext = new InitialContext(); Context envContext = (Context)initContext.lookup("java:/comp/env");//固定,不需要修改 DataSource ds = (DataSource)envContext.lookup(jdbc/sqlserver);
-
全局的JNDI:
在tomcat的安装目录下的conf下的server.xml文件中的GlobalNamingResources标签下加入(一局部JNDI在context.xml文件中的resource配置信息)。
在Web项目中的META-INF下的context中配置
//global中的名字要与server.xml中的名称一样,而这里的name表示当前要使用名称。 <ResourceLink name="jdbc/sqlserver" global="jdbc/sqlserver" type="javax.sql.DataSource"/>
5. 单例模式
系统运行期间,有且仅有一个实例。
- 一个类只有一个实例——最基本的要求
- 只提供私有构造器
- 它必须自行创建这个实例
- 定义了静态的该类私有对象
- 它必须自行向整个系统提供这个实例
- 提供一个静态的公有方法,返回创建或者获取本身的静态私有对象
在整个程序运行期间,有且仅有一个实例。若违背这一点,所设计的类就不是单例类。
5.1 懒汉模式
在类加载时不创建实例,采用延迟加载的方式,在运行调用时创建实例。
特点:
线程不安全、延迟加载(lazy loading)
public class ConfigManager1 {private static ConfigManager1 configManager1 = null;private static Properties properties = new Properties();public ConfigManager1(){try {InputStream is = ConfigManager1.class.getClassLoader().getResourceAsStream("jdbc.properties");//将字节流转换为properties对象properties.load(is);} catch (IOException e) {throw new RuntimeException(e);}}public synchronized static ConfigManager1 getConfigManager1(){if(configManager1==null){configManager1 = new ConfigManager1();}return configManager1;}public String getString(String key){return properties.getProperty(key);}
}
BaseDao:
//1.加载数据库驱动
Class.forName(ConfigManager.getString("mysql.driver"));
conn = DriverManager.getConnection(ConfigManager.getString("mysql.url"),ConfigManager.getString("mysql.uname"),ConfigManager.getString("mysql.upwd")
);
5.2 饿汉模式
在类加载的时候,就完成初始化。
特点:线程安全、不具备延迟加载特性
单例模式 | 懒汉模式 | 饿汉模式 |
---|---|---|
概念 | 在类加载时不创建实例,采用延迟加载的方式,在运行调用时创建实例 | 在类加载的时候,就完成初始化 |
特点 | 类加载速度快,但是运行时获取对象的速度较慢。——时间换空间” | 类加载较慢,但获取对象速度快。——“空间换时间” |
延迟加载(lazy loading) | 具备 | 不具备 |
线程安全 | 线程不安全 | 线程安全 |
public class ConfigManager1 {private static ConfigManager1 configManager1 = null;private static Properties properties = new Properties();public ConfigManager1(){try {InputStream is = ConfigManager1.class.getClassLoader().getResourceAsStream("jdbc.properties");//将字节流转换为properties对象properties.load(is);} catch (IOException e) {throw new RuntimeException(e);}}public synchronized static ConfigManager1 getConfigManager1(){if(configManager1==null){configManager1 = new ConfigManager1();}return configManager1;}public String getString(String key){return properties.getProperty(key);}
}
BaseDao:
//1.加载数据库驱动
Class.forName(ConfigManager1.getConfigManager1().getString("mysql.driver"));
conn = DriverManager.getConnection(ConfigManager1.getConfigManager1().getString("mysql.url"),ConfigManager1.getConfigManager1().getString("mysql.uname"),ConfigManager1.getConfigManager1().getString("mysql.upwd")
);