一、数据库连接总结
1、使用DriverManager.getConnection(url, user, password)
JDBCUtils
public class JDBCUtils {
//定义相关的属性(4个), 因为只需要一份,因此,我们做出static
private static String user; //用户名
private static String password; //密码
private static String url; //url
private static String driver; //驱动名
//在static代码块去初始化
static {
try {
Properties properties = new Properties();
properties.load(new FileInputStream("src\\mysql.properties"));
//读取相关的属性值
user = properties.getProperty("user");
password = properties.getProperty("password");
url = properties.getProperty("url");
driver = properties.getProperty("driver");
} catch (IOException e) {
//在实际开发中,我们可以这样处理
//1. 将编译异常转成 运行异常
//2. 调用者,可以选择捕获该异常,也可以选择默认处理该异常,比较方便.
throw new RuntimeException(e);
}
}
//连接数据库, 返回Connection
public static Connection getConnection() {
try {
return DriverManager.getConnection(url, user, password);
} catch (SQLException e) {
//1. 将编译异常转成 运行异常
//2. 调用者,可以选择捕获该异常,也可以选择默认处理该异常,比较方便.
throw new RuntimeException(e);
}
}
//关闭相关资源
/*
1. ResultSet 结果集
2. Statement 或者 PreparedStatement
3. Connection
4. 如果需要关闭资源,就传入对象,否则传入 null
*/
public static void close(ResultSet set, Statement statement, Connection connection) {
//判断是否为null
try {
if (set != null) {
set.close();
}
if (statement != null) {
statement.close();
}
if (connection != null) {
connection.close();
}
} catch (SQLException e) {
//将编译异常转成运行异常抛出
throw new RuntimeException(e);
}
}
}
JDBCUtils使用操作增删改查SQL语句:
public class JDBCUtils_Use {
@Test
public void testSelect() {
//1. 得到连接
Connection connection = null;
//2. 组织一个sql
String sql = "select * from actor where id = ?";
PreparedStatement preparedStatement = null;
ResultSet set = null;
//3. 创建PreparedStatement 对象
try {
connection = JDBCUtils.getConnection();
System.out.println(connection.getClass()); //com.mysql.jdbc.JDBC4Connection
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1, 1);//给?号赋值
//执行, 得到结果集
set = preparedStatement.executeQuery();
//遍历该结果集
while (set.next()) {
int id = set.getInt("id");
String name = set.getString("name");
String sex = set.getString("sex");
Date borndate = set.getDate("borndate");
String phone = set.getString("phone");
System.out.println(id + "\t" + name + "\t" + sex + "\t" + borndate + "\t" + phone);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
//关闭资源
JDBCUtils.close(set, preparedStatement, connection);
}
}
@Test
public void testDML() {//insert , update, delete
//1. 得到连接
Connection connection = null;
//2. 组织一个sql
String sql = "update actor set name = ? where id = ?";
// 测试 delete 和 insert ,自己玩.
PreparedStatement preparedStatement = null;
//3. 创建PreparedStatement 对象
try {
connection = JDBCUtils.getConnection();
preparedStatement = connection.prepareStatement(sql);
//给占位符赋值
preparedStatement.setString(1, "周星驰");
preparedStatement.setInt(2, 4);
//执行
preparedStatement.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
//关闭资源
JDBCUtils.close(null, preparedStatement, connection);
}
}
}
2、数据库连接池
C3P0:
//1. 创建一个数据源对象,引入相关jar包,使用ComboPooledDataSource()创建对象获得多个连接的连接池
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
//2、注意:连接管理是由 comboPooledDataSource 来管理 comboPooledDataSource.setDriverClass(driver);
comboPooledDataSource.setJdbcUrl(url);
comboPooledDataSource.setUser(user); comboPooledDataSource.setPassword(password);
3、设置初始化连接数
comboPooledDataSource.setInitialPoolSize(10);
最大连接数
comboPooledDataSource.setMaxPoolSize(50);
4、连接这个方法就是从 DataSource 接口实现的:
Connection connection = comboPooledDataSource.getConnection();
或者使用配置文件:
ComboPooledDataSource comboPooledDataSource
= new ComboPooledDataSource("pool_name");
建立连接与上同,不用单独设置参数(配置文件)连接方法从 DataSource 接口实现:
Connection connection = comboPooledDataSource.getConnection();
Druid(德鲁伊):
1、加入 Druid jar包,加入 配置文件 druid.properties , 将该文件拷贝项目的src目录
2、创建一个数据源对象,使用DruidDataSourceFactory.createDataSource(properties);获得,创建DataSource对象,德鲁伊数据源工厂:
DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
3、连接这个方法就是从 DataSource 接口实现的:
Connection connection = dataSource.getConnection();
无论是C3P0的ComboPooledDataSource还是Druid的DruidDataSourceFactory都实现了DataSource接口,可以由动态绑定进行定义声名。可以将连接和关闭写成一个工具类
但是只是连接的问题解决了,执行SQL语句仍需要connection.ProparedStatement(sql)
sql拱顶不能通过参数传入。
preparedStatement = connection.prepareStatement(sql);
//给第一个?号赋值为1
preparedStatement.setInt(1, 1);
//执行, 得到结果集
set =preparedStatement.executeQuery();
二、 Apache—DBUtils总结
DbUtils类是Apache组织开发提供,解决了结果集复用(javabean+集合接收结果集)以及连接执行返回一条语句即可。
1、使用 DBUtils 类和接口 , 先引入DBUtils 相关的jar , 加入到本Project
2、得到 连接 (druid)
Connection connection = JDBCUtilsByDruid.getConnection();
3、 创建 QueryRunner
QueryRunner queryRunner = new QueryRunner();
4、之前connect.PrepareStatement(sql)和ResultSet以及PrepareStatement.setInt(1,1)
connection:Druid工具得到的连接
sql:要执行的查询语句
new BeanListHandler<>(Actor.class):接收查询结果集到集合中,且集合元素为Actor类型
1:就是给 sql 语句中的? 赋值,可以有多个值,因为是可变参数Object... params
List<Actor> list
= queryRunner.query(connection, sql, new BeanListHandler<>(Actor.class), 1);
目前:建立连接使用Druid(德鲁伊)连接池,执行SQL以及保存结果集使用Apache中的DBUtils工具
即:Apache-DBUtils+Druid简化了JDBC的开发
三、DAO(Data Access Object数据访问对象)
1、DAO 和增删改查通用方法-BasicDao
1.1、问题引入
虽然Apache-DBUtils+Druid简化了JDBC的开发,但还有不足:
1、SQL语句固定,不能通过参数传入,通用性不好,需要进行改进,更方便执行增删改查
2、对于select操作,如果有返回值,返回类型不能固定,需要使用泛型
3、将来的表很多,业务需求复杂,不可能只靠一个Java类完成
因此,引出DAO
使用的依然是Apache-DBUtils+Druid,只不过再B阿思翠DAO类中有各自的函数取调用Apache-DBUtils下的QueryRunner类下的各种操作方法,实现封装。
1.2、基本说明
1、DAO:data access object数据访问对象
2、这样的通用类,称为BasicDAO,是专门和数据交互的,即完成对数据库(表)的CRUD操作
3、再BasicDAO基础上,实现一张表对应一个DAO,更好的完成功能。比如Customer表--对应Customer.java类(javabean、domain)---对应一个CustomerDAO.java,,即操作Customer表使用CustomerDAO类操作,操作Goods表使用GoodsDAO类操作,他们都继承于BasicDAO类
简单示例:
1、utils包----放工具类(连接和关闭数据库)
2、domain---存放表中的属性类,如admin表,有用户名列和密码列,domian包里有一个Admin类,有属性userNmae和password两个属性对应这表的字段,用来接收结果集存放在集合中,复用。
3、dao包---存放XxxDAO和BasicDAO类,XxxDAO对应某张表,也对应某个domain中的类
4、test---写测试类
utils包:JDBCUtilsByDruid---通过Druid(德鲁伊)DataSource接口连接池建立的连接和关闭的工具类
public class JDBCUtilsByDruid { private static DataSource ds; //在静态代码块完成 ds初始化 static { Properties properties = new Properties(); try { properties.load(new FileInputStream("src\\druid.properties")); ds = DruidDataSourceFactory.createDataSource(properties); } catch (Exception e) { e.printStackTrace(); } } //编写getConnection方法 public static Connection getConnection() throws SQLException { return ds.getConnection(); } //关闭连接, 老师再次强调: 在数据库连接池技术中,close 不是真的断掉连接 //而是把使用的Connection对象放回连接池 public static void close(ResultSet resultSet, Statement statement, Connection connection) { try { if (resultSet != null) { resultSet.close(); } if (statement != null) { statement.close(); } if (connection != null) { connection.close(); } } catch (SQLException e) { throw new RuntimeException(e); } } }
domain包---Actor类(Javabean,POJO,Domian对象),操作Actor表,属性和Actor表中各字段对应
public class Actor { //Javabean, POJO, Domain对象 private Integer id; private String name; private String sex; private Date borndate; private String phone; public Actor() { //一定要给一个无参构造器[反射需要] } public Actor(Integer id, String name, String sex, Date borndate, String phone) { this.id = id; this.name = name; this.sex = sex; this.borndate = borndate; this.phone = phone; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public Date getBorndate() { return borndate; } public void setBorndate(Date borndate) { this.borndate = borndate; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } @Override public String toString() { return "\nActor{" + "id=" + id + ", name='" + name + '\'' + ", sex='" + sex + '\'' + ", borndate=" + borndate + ", phone='" + phone + '\'' + '}'; } }
dao包--- 存放ActorDAO和BasicDAO类---实现对Actor表操作
连接由Druid连接池建立,操作由Apache--dautils包下的QueryRunner类执行
- BasicDAO类中有方法update(Sting sql,Object...parameters),该方法下调用QueryRunner的update(connection, sql, parameters)方法实现增删改的操作。
- BasicDAO类中有方法:public List<T> queryMulti(String sql, Class<T> clazz, Object... parameters),返回的是一个list集合列表,泛型表示列表存放的类型,该方法下调用QueryRunner的query(connection, sql, new BeanListHandler<T>(clazz), parameters
)方法实现查找并返回结果集的集合- BasicDAO类中有方法:public T querySingle(String sql, Class<T> clazz, Object... parameters),返回的是的那行查询的结果集,因此不用集合保存。该方法下将调用QueryRunner的query(connection, sql, new BeanHandler<T>(clazz), parameters);
- 查询单行单列的数据
public class BasicDAO<T> { //泛型指定具体类型 // Apeche---DBUtils private QueryRunner qr = new QueryRunner(); //开发通用的dml方法, 针对任意的表 public int update(String sql, Object... parameters) { Connection connection = null; try { connection = JDBCUtilsByDruid.getConnection(); int update = qr.update(connection, sql, parameters); return update; } catch (SQLException e) { throw new RuntimeException(e); //将编译异常->运行异常 ,抛出 } finally { JDBCUtilsByDruid.close(null, null, connection); } } //返回多个对象(即查询的结果是多行), 针对任意表 /** * * @param sql sql 语句,可以有 ? * @param clazz 传入一个类的Class对象 比如 Actor.class * @param parameters 传入 ? 的具体的值,可以是多个 * @return 根据Actor.class 返回对应的 ArrayList 集合 */ public List<T> queryMulti(String sql, Class<T> clazz, Object... parameters) { Connection connection = null; try { connection = JDBCUtilsByDruid.getConnection(); return qr.query(connection, sql, new BeanListHandler<T>(clazz), parameters); } catch (SQLException e) { throw new RuntimeException(e); //将编译异常->运行异常 ,抛出 } finally { JDBCUtilsByDruid.close(null, null, connection); } } //查询单行结果 的通用方法 public T querySingle(String sql, Class<T> clazz, Object... parameters) { Connection connection = null; try { connection = JDBCUtilsByDruid.getConnection(); return qr.query(connection, sql, new BeanHandler<T>(clazz), parameters); } catch (SQLException e) { throw new RuntimeException(e); //将编译异常->运行异常 ,抛出 } finally { JDBCUtilsByDruid.close(null, null, connection); } } //查询单行单列的方法,即返回单值的方法 public Object queryScalar(String sql, Object... parameters) { Connection connection = null; try { connection = JDBCUtilsByDruid.getConnection(); return qr.query(connection, sql, new ScalarHandler(), parameters); } catch (SQLException e) { throw new RuntimeException(e); //将编译异常->运行异常 ,抛出 } finally { JDBCUtilsByDruid.close(null, null, connection); } } }
public class ActorDAO extends BasicDAO<Actor> { //1. 就有 BasicDAO 的方法 //2. 根据业务需求,可以编写特有的方法. }
ActorDAO继承BasicDAO类,拥有了BasicDAO的所有方法
test包---测试类 TestDAO
操作Actor表就创建ActorDAO对象(继承了BasicDAO,动态绑定机制)
public class TestDAO { //测试ActorDAO 对actor表crud操作 @Test public void testActorDAO() { ActorDAO actorDAO = new ActorDAO(); //1. 查询,动态绑定机制 List<Actor> actors = actorDAO.queryMulti("select * from actor where id >= ?", Actor.class, 1); System.out.println("===查询结果==="); for (Actor actor : actors) { System.out.println(actor); } //2. 查询单行记录 Actor actor = actorDAO.querySingle("select * from actor where id = ?", Actor.class, 6); System.out.println("====查询单行结果===="); System.out.println(actor); //3. 查询单行单列 Object o = actorDAO.queryScalar("select name from actor where id = ?", 6); System.out.println("====查询单行单列值==="); System.out.println(o); //4. dml操作 insert ,update, delete int update = actorDAO.update("insert into actor values(null, ?, ?, ?, ?)", "张无忌", "男", "2000-11-11", "999"); System.out.println(update > 0 ? "执行成功" : "执行没有影响表"); } }