一、JDBC JDBC有关的类:都在java.sql 和 javax.sql 包下.
1.数据准备 这里假设已经在数据库中新建立了mydb4数据库,并且也插入了一些数据,
并且还需要导入一个jar包mysql-connector-java-5.1.17jar(可从官网下载)
2.JDBC 编程步骤 **步骤1:**装载驱动 DriverManager.registerDriver(new Driver());
tips:在装载驱动的时候推荐使用**Class.forName(“com.mysql.jdbc.Driver”);**
一、查看Driver的源代码可以看到,如果采用此种方式,会导致驱动程序注册两次 ,也就是在内存中会有两个Driver对象。 二、程序依赖mysql的api,脱离mysql的jar包,程序将无法编译,将来程序切换底层数据库将会非常麻烦。**
**步骤2:建**立连接 Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb4", "root", "111");
步骤3:操作数据库
1 2 3 4 5 6 7 8 9 10 11 Statement statement = conn.createStatement(); ResultSet rs = statement.executeQuery(sql); while (rs.next()) { System.out.println(rs.getString("username" )); System.out.println(rs.getString("email" )); }
步骤4 :释放资源
1 2 3 4 5 rs.close(); statement.close(); conn.close();
3.一步到位的操作方式 (更加面向对象&&解决SQL注入问题):
将重复的内容 提取到JDBCUtils工具类中:
提供两种版本分别是硬编码和软编码
硬编码(信息写入到程序中):
JDBCUtils工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 public class JDBCUtils { private static final String driverClass = "com.mysql.jdbc.Driver" ; private static final String url = "jdbc:mysql:///mydb4?" ; private static final String user = "root" ; private static final String password = "111" ; public static void loadDriver () { try { Class.forName(driverClass); } catch (ClassNotFoundException e) { e.printStackTrace(); throw new RuntimeException("驱动加载失败!" ); } } public static Connection getConnection () throws SQLException { Connection conn = DriverManager.getConnection(url, user, password); return conn; } public static void release (Connection conn, Statement stmt, ResultSet rs) { if (rs != null ) { try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } rs = null ; } release(conn, stmt); } public static void release (Connection conn, Statement stmt) { if (stmt != null ) { try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); } stmt = null ; } if (conn != null ) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } conn = null ; } } }
测试类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 @Test public void test_query () { JDBCUtils.loadDriver(); Connection conn = null ; Statement stmt = null ; ResultSet rs = null ; try { conn = JDBCUtils.getConnection(); String sql = "select * from user;" ; stmt = conn.createStatement(); rs = stmt.executeQuery(sql); while (rs.next()) { String username = rs.getString("username" ); String password = rs.getString("password" ); System.out.println(username + " = " + password); } } catch (SQLException e) { e.printStackTrace(); } finally { JDBCUtils.release(conn, stmt, rs); } }
软编码:从配置文件中读取(配置文件名字jdbc.properties)
1 2 3 4 5 6 7 #配置文件 #jdbc.properties #mysql driverClass=com.mysql.cj.jdbc.Driver url=jdbc:mysql: user=root passwrod=111
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 public class JDBCUtils { private static String driverClass; private static String url; private static String username; private static String password; static { Properties prop = new Properties(); try { prop.load(new FileReader("jdbc.properties" )); driverClass = prop.getProperty("driverClass" ); url = prop.getProperty("url" ); username = prop.getProperty("username" ); password = prop.getProperty("password" ); loadDriver(); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException("文件资源加载失败!" ); } } public static void loadDriver () { try { Class.forName(driverClass); } catch (ClassNotFoundException e) { throw new RuntimeException("驱动加载失败!" ); } } public static Connection getConnection () throws SQLException { return DriverManager.getConnection(url, username, password); } public static void release (Connection conn, Statement stmt, ResultSet rs) { if (rs != null ) { try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } rs = null ; } release(conn, stmt); } public static void release (Connection conn, Statement stmt) { if (stmt != null ) { try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); } stmt = null ; } if (conn != null ) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } conn = null ; } } }
测试类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 @Test public void test_query () { Connection conn = null ; Statement stmt = null ; ResultSet rs = null ; try { conn = JDBCUtils.getConnection(); String sql = "select * from user where username = ? and password = ?;" ; stmt = conn.prepareStatement(sql); stmt.setString(1 , username); stmt.setString(2 , password); rs = stmt.executeQuery(); if (rs.next()) { int id = rs.getInt("id" ); String u_name = rs.getString("username" ); String u_pwd = rs.getString("password" ); String email = rs.getString("email" ); System.out.println(id + " : " + u_name + " : " + u_pwd + " : " + email); } catch (SQLException e) { e.printStackTrace(); } finally { JDBCUtils.release(conn, stmt, rs); } }
JDBCUtils中避免sql注入问题之后最终版总结:
PreparedStatement的CRUD
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 @Test public void test_update () { Connection conn = null ; PreparedStatement stmt = null ; try { conn = JDBCUtils.getConnection(); String sql = "update user set username = ?, password = ?, email = ? where id = ?;" ; stmt = conn.prepareStatement(sql); stmt.setString(1 , "张三" ); stmt.setString(2 , "888" ); stmt.setString(3 , "zs@qiezi.cn" ); stmt.setInt(4 , 1 ); int affectedRowNum = stmt.executeUpdate(); System.out.println(affectedRowNum); String sql = "delete from user where id = ?;" ; stmt = conn.prepareStatement(sql); stmt.setInt(1 , 4 ); int affectedRowNum = stmt.executeUpdate(); System.out.println(affectedRowNum); String sql = "insert into user values(?,?,?,?);" ; stmt = conn.prepareStatement(sql); stmt.setInt(1 , 4 ); stmt.setString(2 , "赵六" ); stmt.setString(3 , "888" ); stmt.setString(4 , "zl@qiezi.cn" ); int affectedRowNumber = stmt.executeUpdate(); System.out.println(affectedRowNumber); String sql = "select * from user where username = ? and password = ?;" ; stmt = conn.prepareStatement(sql); stmt.setString(1 , username); stmt.setString(2 , password); rs = stmt.executeQuery(); if (rs.next()) { int id = rs.getInt("id" ); String u_name = rs.getString("username" ); String u_pwd = rs.getString("password" ); String email = rs.getString("email" ); System.out.println(id + " : " + u_name + " : " + u_pwd + " : " + email); } } catch (SQLException e) { e.printStackTrace(); } finally { JDBCUtils.release(conn, stmt); } }
二、JdbcTemplate 1.JdbcTemplate 介绍 JDBC已经能够满足大部分用户最基本的需求,但是在使用JDBC时,必须自己来管理数据库资源如:获取PreparedStatement,设置SQL语句参数,关闭连接等步骤。JdbcTemplate就是Spring对JDBC的封装,目的是使JDBC更加易于使用。JdbcTemplate是Spring的一部分
JdbcTemplate处理了资源的建立和释放。他帮助我们避免一些常见的错误,比如忘了总要关闭连接。他运行核心的JDBC工作流,如Statement的建立和执行,而我们只需要提供SQL语句和提取结果。
在JdbcTemplate中执行SQL语句的方法大致分为3类:
\1. execute:可以执行所有SQL语句,一般用于执行DDL语句。
\2. update:用于执行INSERT、UPDATE、DELETE等DML语句。
\3. queryXxx:用于DQL数据查询语句。
** 新增加,新复习
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 DDL (数据定义语言) 数据定义语言 - Data Definition Language 用来定义数据库的对象,如数据表、视图、索引等 create drop alter truncate DML (数据操纵语言) 数据处理语言 - Data Manipulation Language 在数据库表中更新,增加和删除记录 如 update, insert, delete 不包含查询 DCL (数据控制语言) 数据控制语言 – Data Control Language 指用于设置用户权限和控制事务语句 如grant,revoke,if …else ,while ,begin transaction DQL (数据查询语言)(★★★★★) 数据查询语言 – Data Query Language 数据表记录的查询。 select
2.JDBCTemplate使用: API介绍:
1.org.springframework.jdbc.core.JdbcTemplate类方便执行SQL语句
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 public JdbcTemplate (DataSource dataSource) 创建JdbcTemplate对象,方便执行SQL语句 public void execute (final String sql) execute可以执行所有SQL语句,因为没有返回值,一般用于执行DML语句。 public int update (final String sql) 用于执行`INSERT`、`UPDATE`、`DELETE`等DML语句。 public <T> T queryForObject (String sql, Class<T> requiredType, Object... args) : 传入参数, 执行查询语句,返回一个指定类型的数据。 public Map<String, Object> queryForMap (String sql, Object... args) 传入参数,执行查询语句,将一条记录放到一个Map中。 public List<Map<String, Object>> queryForList (String sql, Object... args) 传入参数,执行查询语句,返回一个List集合,List中存放的是Map类型的数据。 public <T> List<T> query (String sql, RowMapper<T> rowMapper) 执行查询语句,返回一个List集合,List中存放的是RowMapper指定类型的数据。 public <T> List<T> query (String sql, RowMapper<T> rowMapper) 执行查询语句,返回一个List集合,List中存放的是RowMapper指定类型的数据。 public class BeanPropertyRowMapper<T> implements RowMapper<T>BeanPropertyRowMapper类实现了RowMapper接口
1.数据准备:
这里采用c3p0数据流连接池,集成到JDBCUtils 工具类中,需要将c3p0的配置文件放入到src目录下
导入依赖的jar包
2.创建JdbcTemplate对象,传入c3p0连接池
3.调用 execute、update、queryXxx等方法
c3p0-config.xml 配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <?xml version="1.0" encoding="UTF-8" ?> <c3p0-config> <!-- 默认配置,c3p0框架默认加载这段默认配置 --> <default -config> <!-- 配置JDBC 四个基本属性 --> <property name="driverClass">com.mysql.cj.jdbc.Driver</property> <property name="jdbcUrl" >jdbc:mysql: <property name="user">root</property> <property name="password">111</property> </default-config> <!-- 可以自定义配置,为这段配置起一个名字,c3p0指定名称加载配置 --> <named-config name="zidingyimingzi" > <property name="driverClass">com.mysql.cj.jdbc.Driver</property> <property name="jdbcUrl" >jdbc:mysql: <property name="user">root</property> <property name="password">111</property> </named-config> </c3p0-config>
JDBCUtils 工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 public class JDBCUtils { private static ComboPooledDataSource dataSource = new ComboPooledDataSource(); public static DataSource getDataSource () { return dataSource; } public static Connection getConnection () throws SQLException { return dataSource.getConnection(); } public static void release (Connection conn, Statement stmt, ResultSet rs) { if (rs != null ) { try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } rs = null ; } release(conn, stmt); } public static void release (Connection conn, Statement stmt) { if (stmt != null ) { try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); } stmt = null ; } if (conn != null ) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } conn = null ; } } }
测试类(实现增改)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 public class JDBCTemplateExecute { public static void main (String[] args) { String sql = "create table product (" + "pid int primary key auto_increment," + "pname varchar(20)," + "price double" + ");" ; JdbcTemplate jdbcTemplate = new JdbcTemplate(JDBCUtils.getDataSource()); jdbcTemplate.execute(sql); String sql = "insert into product values(null, ?, ?);" ; jdbcTemplate.update(sql, "iPhone3GS" , 3333 ); jdbcTemplate.update(sql, "iPhone4" , 5000 ); String sql = "update product set pname = ?, price = ? where pid = ?;" ; int count = jdbcTemplate.update(sql, "XVIII" , 18888 , 10 ); System.out.println("count = " + count); String sql = "delete from product where pid = ?;" ; int count = jdbcTemplate.update(sql, 7 ); System.out.println("count = " + count); } }
总结:JdbcTemplate的update方法用于执行DML语句。同时还可以在SQL语句中使用?占位,在update方法的Object… args可变参数中传入对应的参数。
测试类(实现查询)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 @Test public void test1 () { JdbcTemplate jdbcTemplate = new JdbcTemplate(JDBCUtils.getDataSource()); String sql = "select pname from product where price = 7777" ; String pname = jdbcTemplate.queryForObject(sql, String.class); System.out.println("pname = " + pname); String sql = "select * from product where pid = ?;" ; Map<String, Object> map = jdbcTemplate.queryForMap(sql, 6 ); System.out.println("map = " + map); String sql = "select * from product where pid < ?;" ; List<Map<String, Object>> list = jdbcTemplate.queryForList(sql, 8 ); for (Map<String, Object> map : list) { System.out.println(map); } 1 . 定义Product类2 . 创建JdbcTemplate对象3 . 编写查询的SQL语句4 . 使用JdbcTemplate对象的query方法,并传入RowMapper匿名内部类5 . 在匿名内部类中将结果集中的一行记录转成一个Product对象 String sql = "select * from product;" ; List<Product> list = jdbcTemplate.query(sql, new RowMapper<Product>() { @Override public Product mapRow (ResultSet rs, int i) throws SQLException { Product product = new Product(); int pid = rs.getInt("pid" ); String pname = rs.getString("pname" ); double price = rs.getDouble("price" ); product.setPid(pid); product.setPname(pname); product.setPrice(price); return product; } }); for (Product product : list) { System.out.println(product); } 1 . 定义Product类2 . 创建JdbcTemplate对象3 . 编写查询的SQL语句4 . 使用JdbcTemplate对象的query方法,并传入BeanPropertyRowMapper对象 String sql = "select * from product;" ; List<Product> list = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(Product.class)); for (Product product : list) { System.out.println(product); } }
总结:
JDBCTemplate的query方法用于执行SQL语句,简化JDBC的代码。同时还可以在SQL语句中使用?占位,在query方法的Object... args可变参数中传入对应的参数。
三、c3p0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 在Hibernate和Spring 都提供对C3P0连接池支持. 导入2 个包 基本操作 ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource(); comboPooledDataSource.setDriverClass("com.mysql.cj.jdbc.Driver" ); comboPooledDataSource.setJdbcUrl("jdbc:mysql:///mydb4?" ); comboPooledDataSource.setUser("root" ); comboPooledDataSource.setPassword("111" ); 常用基本连接池属性 acquireIncrement 如果连接池中连接都被使用了,一次性增长3 个新的连接 initialPoolSize 连接池中初始化连接数量默认:3 maxPoolSize 最大连接池中连接数量默认:15 连接 maxIdleTime 如果连接长时间没有时间,将被回收默认:0 连接永不过期 minPoolSize 连接池中最小连接数量 默认:3
通过c3p0创建数据库连接池对象方式提取到JDBCUtils中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 public class JDBCUtils { private static final ComboPooledDataSource dataSource = new ComboPooledDataSource(); public static Connection getConnection () throws SQLException { return dataSource.getConnection(); } public static void release (Connection conn, Statement stmt, ResultSet rs) { if (rs != null ) { try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } rs = null ; } release(conn, stmt); } public static void release (Connection conn, Statement stmt) { if (stmt != null ) { try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); } stmt = null ; } if (conn != null ) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } conn = null ; } } }
c3p0-config.xml 数据库连接池配置文件 位于src 目录下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <?xml version="1.0" encoding="UTF-8" ?> <c3p0-config> <!-- 默认配置,c3p0框架默认加载这段默认配置 --> <default -config> <!-- 配置JDBC 四个基本属性 --> <property name="driverClass">com.mysql.cj.jdbc.Driver</property> <property name="jdbcUrl" >jdbc:mysql: <property name="user">root</property> <property name="password">111</property> </default-config> <!-- 可以自定义配置,为这段配置起一个名字,c3p0指定名称加载配置 --> <named-config name="zidingyi" > <property name="driverClass">com.mysql.cj.jdbc.Driver</property> <property name="jdbcUrl" >jdbc:mysql: <property name="user">root</property> <property name="password">111</property> </named-config> </c3p0-config>
测试类:
@Test
public void test_jdbcUtils() {
// 需求 : 查询 user 表中的所有数据
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try {
// 1. 建立连接
conn = JDBCUtils.getConnection();
// 2. 操作数据
String sql = "select * from user;";
stmt = conn.prepareStatement(sql);
rs = stmt.executeQuery();
while (rs.next()) {
int id = rs.getInt("id");
String username = rs.getString("username");
String password = rs.getString("password");
String email = rs.getString("email");
System.out.println(id + " : " + username + " : " + password + " : " + email);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 3. 释放资源
JDBCUtils.release(conn, stmt, rs);
}
}
四、druid Druid (德鲁伊) 是阿里巴巴开发的号称为监控而生的数据库连接池,Druid是目前最好的数据库连接池。在功能、性能、扩展性方面,都超过其他数据库连接池,同时加入了日志监控,可以很好的监控DB池连接和SQL的执行情况。Druid已经在阿里巴巴部署了超过600个应用,经过一年多生产环境大规模部署的严苛考验。Druid地址:https://github.com/alibaba/druid
DRUID连接池使用的jar包:
参数
说明
url
连接数据库的url:jdbc:mysql://localhost:3306/mydb
username
数据库的用户名
password
数据库的密码
driverClassName
驱动类名。根据url自动识别,这一项可配可不配,如果不配置druid会根据url自动识别dbType,然后选择相应的driverClassName(建议配置下)
initialSize
初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时
maxActive
最大连接池数量
maxIdle
已经不再使用,配置了也没效果
minIdle
最小连接池数量
maxWait
获取连接时最大等待时间,单位毫秒。
API介绍
com.alibaba.druid.pool.DruidDataSourceFactory类有创建连接池的方法
1 2 public static DataSource createDataSource (Properties properties) 创建一个连接池,连接池的参数使用properties中的数据
tips:我们可以看到DRUID连接池在创建的时候需要一个Properties对象来设置参数,所以我们使用properties文件来保存对应的参数。
DRUID连接池的配置文件名称随便,因为该配置文件需要我们手动实现加载。
druid.properties文件内容:
1 2 3 4 5 6 7 8 9 driverClassName=com.mysql.cj.jdbc.Driver url=jdbc:mysql: username=root password=111 initialSize=5 maxActive=10 maxWait=3000 maxIdle=6 minIdle=3
1.使用步骤: \1. 在src目录下创建一个properties文件,并设置对应参数
\2. 加载properties文件的内容到Properties对象中
\3. 创建DRUID连接池,使用配置文件中的参数
\4. 从DRUID连接池中取出连接
\5. 执行SQL语句
\6. 关闭资源
JDBCUtils 工具类集成 Druid 数据库连接池
public class JDBCUtils {
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 private static final DataSource dataSource;static { Properties prop = new Properties(); try { prop.load(new FileReader("druid.properties" )); dataSource = DruidDataSourceFactory.createDataSource(prop); } catch (Exception e) { throw new RuntimeException("连接池初始化失败!" ); } } public static DataSource getDataSource () { return dataSource; } public static Connection getConnection () throws SQLException { return dataSource.getConnection(); } public static void release (Connection conn, Statement stmt, ResultSet rs) { if (rs != null ) { try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } rs = null ; } release(conn, stmt); } public static void release (Connection conn, Statement stmt) { if (stmt != null ) { try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); } stmt = null ; } if (conn != null ) { try { conn.close(); } catch (SQLException e) { } conn = null ; } } }
测试类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 @Test public void test3 () { Connection conn = null ; PreparedStatement stmt = null ; ResultSet rs = null ; try { conn = JDBCUtils.getConnection(); String sql = "select * from user;" ; stmt = conn.prepareStatement(sql); rs = stmt.executeQuery(); while (rs.next()) { int id = rs.getInt("id" ); String username = rs.getString("username" ); String password = rs.getString("password" ); String email = rs.getString("email" ); System.out.println(id + " : " + username + " : " + password + " : " + email); } } catch (SQLException e) { e.printStackTrace(); } finally { JDBCUtils.release(conn, stmt, rs); } }