JDBC,即Java数据库连接,是SUN公司推出的Java访问数据库的标准规范(接口)。
1. JDBC是一种用于执行SQL语句的Java API。
2. JDBC可以为多种关系数据库提供统一访问入口。
3. JDBC是由一组Java工具类和接口组成。
JDBC开发步骤
1. 注册驱动。
2. 获得连接。
3. 获得语句执行者。
4. 执行sql语句。
5. 处理结果。
6. 释放资源。
a、创建lib目录,用于存放当前项目需要的所有jar包
b、选择jar包,右键执行 bulid path / add to bulid Path
Class.forName("com.mysql.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/demo","root","wu25471396");
扩展url参数
jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=UTF8
//注意:java程序连接数据库的过程中,使用的字符编码是UTF-8。mysql中指定UTF-8编码是UTF8.
方法一:推荐(可以防止SQL注入)
String sql = "select * from tb1_user where uname=? and upassword=? ";
//创建预处理对象
PrepareStatement pstmt = conn.prepareStatement(sql);
//设置参数(给占位符)
pstmt.setString(1,username);
pstmt.setString(2,password);
方法二:
String sql = "select * from tb1_user where uname="+username+" and upassword="+password";
//创建执行sql语句的对象
Statement stmt = conn.createStatement();
ResultSet rs = pstmt.executeQuery();
或(与上面的相对应的)
ResultSet rs = stmt.executeQuery(sql);
rs.close();
stmt.close();
con.close();
public void login1(String username, String password) throws ClassNotFoundException, SQLException {
// 1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
// 2.获取连接
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/web08", "root", "root");
// 3.编写sql语句
String sql = "select * from user where uname=? and upassword=?";
// 4.创建预处理对象
PreparedStatement pstmt = conn.prepareStatement(sql);
// 5.设置参数(给占位符)
pstmt.setString(1, username);
pstmt.setString(2, password);
// 6.执行查询操作
ResultSet rs = pstmt.executeQuery();
// 7.对结果集进行处理
if (rs.next()) {
System.out.println("恭喜您," + username + ",登录成功!");
System.out.println(sql);
} else {
System.out.println("账号或密码错误!");
}
if (rs != null)
rs.close();
if (pstmt != null)
pstmt.close();
if (conn != null)
conn.close();
}
public void login(String username, String password) throws ClassNotFoundException, SQLException {
// 1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
// 2.获取连接
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/web08", "root", "root");
// 3.创建执行sql语句的对象
Statement stmt = conn.createStatement();
// 4.书写一个sql语句
String sql = "select * from user where uname='" + username + "' and upassword='" + password + "'";
// 5.执行sql语句
ResultSet rs = stmt.executeQuery(sql);
// 6.对结果集进行处理
if (rs.next()) {
System.out.println("恭喜您," + username + ",登录成功!");
System.out.println(sql);
} else {
System.out.println("账号或密码错误!");
}
if (rs != null)
rs.close();
if (stmt != null)
stmt.close();
if (conn != null)
conn.close();
}
使用properties配置文件:
1. 文件位置:任意,建议src下
2. 文件名称:任意,扩展名为properties
3. 文件内容:一行一组数据。格式是key=value (key命名自定义,如果多个单词,习惯用点分隔。)
假如文件为:db.properties
内容:
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/demo
username=root
password=wu25471396
JDBCUtils_v1版本:
使用JDK提供的工具类ResourceBundle加载properties文件
public class JDBCUtils_v1 {
private static String driver; //驱动
private static String url; //路径
private static String user; //用户名
private static String password; //密码
/**
* 配置文件只需要加载一次,提供静态代码,当前类被加载到内存执行
*/
static{
//1、使用JDK提供的工具类加载properties文件
/*
* ResourceBundle专门用于处理properties文件的。
* 提供getBundle()方法只需要填写文件即可。
*/
ResourceBundle bundle = ResourceBundle.getBundle("db");
//2、通过key获取需要的值
driver = bundle.getString("driver");
url = bundle.getString("url");
user = bundle.getString("username");
password = bundle.getString("password");
}
/**
* 获取连接
* @return
*/
public static Connection getConnection(){
try {
//1、注册驱动
Class.forName(driver);
//2、获取连接
Connection conn = DriverManager.getConnection(url, user, password);
return conn;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 释放资源
* @param conn
* @param pstmt
* @param rs
*/
public static void close(Connection conn, PreparedStatement pstmt, ResultSet rs){
if (rs != null) {
try {
rs.close();
}catch (SQLException e) {
e.printStackTrace();
}
}
if(pstmt != null ) {
try {
pstmt.close();
}catch (SQLException e) {
e.printStackTrace();
}
}
if(rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
JDBCUtils_v2版本:
采用加载properties文件获得流,然后使用Properties对象进行处理
public class JDBCUtils_v2 {
private static String driver; //驱动
private static String url; //路径
private static String user; //用户名
private static String password; //密码
/**
* 静态代码块加载配置文件信息
*/
static{
try {
// 1.通过当前类获取类加载器
ClassLoader classLoader = JDBCUtils_v2.class.getClassLoader();
// 2.通过类加载器的方法获得一个输入流
InputStream is = classLoader.getResourceAsStream("db.properties");
// 3.创建一个properties对象
Properties props = new Properties();
// 4.加载输入流
props.load(is);
// 5.获取相关参数的值
driver = props.getProperty("driver");
url = props.getProperty("url");
user = props.getProperty("username");
password = props.getProperty("password");
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 获取连接
* @return
*/
public static Connection getConnection(){
Connection conn = null;
try {
//1、注册驱动
Class.forName(driver);
//2、获取连接
conn = DriverManager.getConnection(url, user, password);
} catch (Exception e) {
throw new RuntimeException(e);
}
return conn;
}
/**
* 释放资源
* @param conn
* @param pstmt
* @param rs
*/
public static void close(Connection conn, PreparedStatement pstmt, ResultSet rs){
if (rs != null) {
try {
rs.close();
}catch (SQLException e) {
e.printStackTrace();
}
}
if(pstmt != null ) {
try {
pstmt.close();
}catch (SQLException e) {
e.printStackTrace();
}
}
if(rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
测试JDBCUtils工具
public class TestUtils {
@Test
public void testFindUserById() {
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
// 1.获取连接
conn = JDBCUtils_v1.getConnection();
// 2.编写sql语句
String sql = "select * from user where uid=?";
// 3.获取执行sql语句对象
pstmt = conn.prepareStatement(sql);
// 4.设置参数
pstmt.setInt(1, 2);
// 5.执行查询操作
rs = pstmt.executeQuery();
// 6.处理结果集
while (rs.next()) {
System.out.println(rs.getString(2) + "---------" + rs.getString("upassword"));
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 7.释放资源
JDBCUtils_v1.close(conn, pstmt, rs);
}
}
}
自定义连接池:
MyDataSource.java
public class MyDataSource implements DataSource {
//1.创建1个容器用于存储Connection对象 ,增删操作多用LinkedList
private static LinkedList pool = new LinkedList();
//2.创建5个连接放到容器中去
static{
for (int i = 0; i < 5; i++) {
Connection conn = JDBCUtils_v2.getConnection();
pool.add(conn);
}
}
/**
* 重写获取连接的方法
*/
@Override
public Connection getConnection() throws SQLException {
Connection conn = null;
//3.使用前先判断
if(pool.size()==0){
//4.池子里面没有,我们再创建一些
for (int i = 0; i < 5; i++){
conn = JDBCUtils_v2.getConnection();
pool.add(conn);
}
}
//5.从池子里面获取一个连接对象Connection
conn = pool.remove(0);
return conn;
}
/**
* 归还连接对象到连接池中
*/
public void backConnection(Connection conn){
pool.add(conn);
}
@Override
public PrintWriter getLogWriter() throws SQLException {
return null;
}
@Override
public void setLogWriter(PrintWriter out) throws SQLException {
}
@Override
public void setLoginTimeout(int seconds) throws SQLException {
}
@Override
public int getLoginTimeout() throws SQLException {
return 0;
}
@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
return null;
}
@Override
public T unwrap(Class iface) throws SQLException {
return null;
}
@Override
public boolean isWrapperFor(Class> iface) throws SQLException {
return false;
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
return null;
}
}
TestMyDataSource.java
public class TestMyDataSource {
/**
* 添加用户
* 使用未改造过的connection
*/
@Test
public void testAddUser(){
Connection conn = null;
PreparedStatement pstmt = null;
//1. 创建自定义连接池对象
MyDataSource dataSource = new MyDataSource();
try {
// 2.从池子中获取连接
conn = dataSource.getConnection();
String sql = "insert into user values(null,?,?)";
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, "貂蝉");
pstmt.setString(2, "吕布");
int rows = pstmt.executeUpdate();
if (rows > 0) {
System.out.println("添加成功");
} else {
System.out.println("添加失败");
}
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
dataSource.backConnection(conn);
}
}
}
自定义连接池:方法增强
上述存在的问题:使用自定义连接池,则需要记住自定义连接池中的API。
例如:
当返还资源是,我们希望仍然调用close()方法。此时就需要增添close()方法。
方法增强的三种模式:
1. 继承:子类继承父类,将父类的方法进行重写,从而增强。
使用前提: 必须有父类,且存在继承关系。
2. 装饰者模式:此设计模式专门用于增强方法。
使用前提: 必须有接口。
缺点: 需要实现接口的所有方法。
3. 动态代理: 在运行时动态创建代理类,完成增强操作。与装饰者相似。
使用前提: 必须有接口。
难点: 需要反射技术。
采用装饰者模式:
装饰类:MyConnection.java
/**
* 装饰类MyConnection 实现同一个接口Connection
* @author ludada
*
*/
public class MyConnection implements Connection{
//定义一个变量
private Connection conn;
private LinkedList pool;
//编写一个构造方法(参数使用了面相对象的多态特性)
public MyConnection(Connection conn,LinkedList pool) {
this.conn = conn;
this.pool = pool;
}
//书写需要增强的方法
@Override
public void close() throws SQLException {
pool.add(conn);
}
/**
* 此方法必须覆盖,否则会出现空指针异常
*/
@Override
public PreparedStatement prepareStatement(String sql) throws SQLException {
return conn.prepareStatement(sql);
}
}
MyDataSource1.java
public class MyDataSource1 implements DataSource{
//1.创建1个容器用于存储Connection对象
private static LinkedList pool = new LinkedList();
//2.创建5个连接放到容器中去
static{
for (int i=0; i < 5; i++) {
Connection conn = JDBCUtils_v2.getConnection();
//放入池子中connection对象已经经过改造了
MyConnection myconn = new MyConnection(conn, pool);
pool.add(myconn);
}
}
/**
* 重写获取连接的方法
*/
@Override
public Connection getConnection() throws SQLException {
Connection conn = null;
if(pool.size()==0) {
for (int i = 0; i < 5; i++) {
conn = JDBCUtils_v2.getConnection();
//放入池子中connection对象已经经过改造了
MyConnection myconn = new MyConnection(conn, pool);
pool.add(myconn);
}
}
conn = pool.remove(0);
return conn;
}
}
测试类:
@Test
public void testAddUser1() {
Connection conn = null;
PreparedStatement pstmt = null;
// 1.创建自定义连接池对象
DataSource dataSource = new MyDataSource1();
try {
conn = dataSource.getConnection();
String sql = "insert into user values(null,?,?)";
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, "牡丹");
pstmt.setString(2, "仙子");
int rows = pstmt.executeUpdate();
if(rows > 0) {
System.out.println("添加成功");
}else {
System.out.println("添加失败");
}
} catch (Exception e) {
throw new RuntimeException(e);
}finally{
//注意:此处的conn是利用的多态,JDBCUtils_v2.close()中调用的conn.close()是MyConnection中close的重写方法。
JDBCUtils_v2.close(conn, pstmt, null);;
}
}
1、C3P0
C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate,Spring等。
2、C3P0的使用
C3p0-0.9.2-pre5.jar
和mchange-commons-java-0.2.3.jar
(可以没有)
<c3p0-config>
<default-config>
<property name="driverClass">com.mysql.jdbc.Driverproperty>
<property name="jdbcUrl">jdbc:mysql:///demoproperty>
<property name="user">rootproperty>
<property name="password">wu25471396property>
<property name="initialPoolSize">5property>
<property name="maxPoolSize">20property>
default-config>
<named-config name="xiaobai">
<property name="driverClass">com.mysql.jdbc.Driverproperty>
<property name="jdbcUrl">jdbc:mysql:///demoproperty>
<property name="user">rootproperty>
<property name="password">wu25471396property>
named-config>
c3p0-config>
/**
* C3P0提供的核心工具类:ComboPooledDataSource,
* 如果要使用连接池,必须
* @author ludada
*
*/
public class C3P0Utils {
/*
* C3P0提供的核心工具类:ComboPooledDataSource,
* 如果要使用连接池,必须创建该实例对象
*/
//使用配置文件"默认配置"
//private static ComboPooledDataSource dataSource = new ComboPooledDataSource();
//使用配置文件"命名配置"
private static ComboPooledDataSource dataSource = new ComboPooledDataSource("xiaobai");
/**
* 获得数据源(连接池)
* @return
*/
public static DataSource getDataSource(){
return dataSource;
}
public static Connection getConnection(){
try {
return dataSource.getConnection();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
public class TestC3P0 {
@Test
public void testAddUser() {
Connection conn = null;
PreparedStatement pstmt = null;
try {
conn = C3P0Utils.getConnection();
String sql = "insert into user values(null,?,?)";
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, "靖公主");
pstmt.setString(2, "严霜");
int rows = pstmt.executeUpdate();
if (rows > 0){
System.out.println("添加成功");
}else {
System.out.println("添加失败");
}
} catch (SQLException e) {
throw new RuntimeException(e);
}finally{
JDBCUtils_v2.close(conn, pstmt, null);
}
}
}
1、DBCP也是一个开源的连接池,是tomcat内置的连接池。
2、DBCP的使用:
1. 导入jar包
commons-dbcp-1.4.jar
和commons-pool-1.6.jar
2. 配置文件
配置文件名称:*.properties
注意: 文件中用户的key必须为username
配置文件位置:任意,建议src (classpath/类路径)
配置文件内容:不能中文
3. 编写工具类
public class DBCPUtils {
private static DataSource dataSource;
static{
try {
//1.加载找properties文件输入流
InputStream is = DBCPUtils.class.getClassLoader().getResourceAsStream("db.properties");
//2.加载输入流
Properties props = new Properties();
props.load(is);
//3.创建数据源
dataSource = BasicDataSourceFactory.createDataSource(props);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static DataSource getDataSource(){
return dataSource;
}
public static Connection getConnection(){
try {
return dataSource.getConnection();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
public class TestDBCP {
@Test
public void testUpdateUserById(){
Connection conn = null;
PreparedStatement pstmt = null;
try {
conn = DBCPUtils.getConnection();
String sql = "update user set upassword=? where uid=?";
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, "严霜");
pstmt.setInt(2, 7);
int rows = pstmt.executeUpdate();
System.out.println(rows);
if(rows > 0) {
System.out.println("修改成功");
}else{
System.out.println("修改失败");
}
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
JDBCUtils_v2.close(conn, pstmt, null);
}
}
**DBUtils:**apache commons组件的一个成员,封装了对JDBC的操作,简化了JDBC操作。
JavaBean 就是一个类,在开发中常用与封装数据。需要以下要求:
1. 需要实现接口:java.io.Serializable
,常常偷懒省略了。
2. 提供私有字段: private 类型 字段名;
3. 提供 get/set 方法;
4. 提供无参构造方法
例:
public class User {
private int uid;
private String uname;
private String upassword;
public User(){
}
public int getUid() {
return uid;
}
public void setUid(int uid) {
this.uid = uid;
}
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
public String getUpassword() {
return upassword;
}
public void setUpassword(String upassword) {
this.upassword = upassword;
}
}
1、QueryRunner核心类
- QueryRunner(DataSource ds),提供数据源(连接池),DBUtils底层子对维护connection
- update(String sql, Object…params),执行更新数据。
- query(String sql,ResultSetHandlerrsh,Object…params),执行查询
2、ResultSetHandler结果处理类
我们知道在执行select语句之后得到的是ResultSet,然后我们还需要对ResultSet进行转换,得到最终我们想要的数据。你可以希望把ResultSet的数据放到一个List中,也可能想把数据放到一个Map中,或是一个Bean中。
DBUtils提供了一个接口ResultSetHandler,它就是用来ResultSe它就是用来ResultSet转换成目标类型的工具t转换成目标类型的工具。你可以自己去实现这个接口,把ResultSet转换成你想要的类型。
DBUtils提供了很多个ResultSetHandler接口的实现,这些实现已经基本够用了,我们通常不用自己去实现ResultSet接口了。
ResultSetHandler接口的实现 | 解释 |
---|---|
BeanHandler | 单行处理器!把结果集转换成Bean,该处理器需要Class参数,即Bean的类型 |
BeanListHandler | 多行处理器!把结果集转换成List |
ScalarHandler | 单行单列处理器!把结果集转换成Object。一般用于聚集查询,例如select count(*) from tab_student。 |
MapHandler | 单行处理器!把结果集转换成Map |