目录
2.ORM 对象关系映射(Object Relational Mapping)
3.DAO 数据库访问对象(DataAccess Object)
JDBC优化
1.元数据
在jdbc中获取数据库的定义,例如:数据库、表、列的定义信息。就用到元数据。
在jdbc中可以获取: 数据库元数据、参数元数据、结果集元数据(元数据定义相关api: . . .MetaData)
// 首先获取连接
Connection conn = JdbcUtil.getConnection();
--------------------------------------------------------------------------
// 1.数据库元数据 (-----通过连接,获取数据库信息-----)
DatabaseMetaData metaData = conn.getMetaData();
metaData.getURL():返回一个String类对象,代表数据库的URL。
metaData.getUserName():返回连接当前数据库管理系统的用户名。
metaData.getDatabaseProductName():返回数据库的产品名称。
metaData.getDatabaseProductVersion():返回数据库的版本号。
metaData.getDriverName():返回驱动驱动程序的名称。
metaData.getDriverVersion():返回驱动程序的版本号。
metaData.isReadOnly():返回一个boolean值,指示数据库是否只允许读操作。
--------------------------------------------------------------------------
String sql = "select * from dept where deptid=? and deptName=?";
PreparedStatement pstmt = conn.prepareStatement(sql);
//2. 参数元数据 (-----通过预编译sql语句,获取它的参数个数与类型-----)
ParameterMetaData p_metaDate = pstmt.getParameterMetaData();
p_metaDate.getParameterCount() :获得指定参数的个数
p_metaDate.getParameterType(int param) :获得指定参数的sql类型
--------------------------------------------------------------------------
PreparedStatement pstmt = conn.prepareStatement(sql);
ResultSet rs = pstmt.executeQuery();
// 3.得到结果集元数据 (-----通过rs结果集元数据,得到列的名称-----)
ResultSetMetaData rs_metaData = rs.getMetaData();
while (rs.next()) {
int count = rs_metaData.getColumnCount(): 返回resultset对象的列数
for (int i=0; i<count; i++) {
String columnName = rs_metaData.getColumnName(int column): 获得指定列的名称
rs_metaData.getColumnTypeName(int column):获得指定列的类型
//根据列名称获取值
rs.getObject(columnName);
}
}
2.ORM 对象关系映射(Object Relational Mapping)
思路:一个对象,对应数据库里的一条记录
设计:按照这个思路设计一些方法,封装数据库操作,对外提供可操作的对象
结果:不需要理解数据库操作,只调用对象方法
通过使用描述对象和数据库之间映射的元数据,将面向对象语言程序中的对象自动持久化到关系数据库中。
常用O-R Mapping映射工具:
Hibernate
Ibatis
Commons DBUtils(只是对JDBC简单封装)
3.DAO 数据库访问对象(DataAccess Object)
运用了ORM中的思路,把数据库相关的操作都封装在这个类里面,其他地方看不到JDBC的代码
//数据库=DAO对象
//数据库操作=DAO对象方法
public interface DAO{
//增加
public void add(Hero hero);
//修改
public void update(Hero hero);
//删除
public void delete(int id);
//获取
public Hero get(int id);
//查询
public List<Hero> list();
//分页查询
public List<Hero> list(int start, int count);
}
//具体实现数据库对象操作
public class HeroDAO implements DAO{
//加载数据库驱动
public HeroDAO() {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
//获取数据库连接
public Connection getConnection() throws SQLException {
return DriverManager.getConnection("url地址", "用户名","密码");
}
//add方法实现
public void add(Hero hero) {
String sql = "insert into hero values(null,?,?,?)";
try (Connection c = getConnection(); PreparedStatement ps = c.prepareStatement(sql);) {
ps.setString(1, hero.name);
ps.setFloat(2, hero.hp);
ps.setInt(3, hero.damage);
ps.execute();
ResultSet rs = ps.getGeneratedKeys();
if (rs.next()) {
int id = rs.getInt(1);
hero.id = id;
}
} catch (SQLException e) {
e.printStackTrace();
}
}
......实现其他方法
}
BeanUtils组件
程序中对javabean的操作很频繁, 所以apache提供了一套开源的api,方便对javabean的操作。即BeanUtils组件:作用是简化javabean的操作!
使用BenUtils组件:
- 引入commons-beanutils-1.8.3.jar核心包
- 引入日志支持包: commons-logging-1.1.3.jar
注:缺少日志jar文件,报错:java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory
基本用法:
1. 对象属性的拷贝,赋值给javabean(反射原理)
BeanUtils.copyProperty(bean, "name", value);
BeanUtils.setProperty(bean, "age", value);
2. 对象的拷贝
BeanUtils.copyProperties(newAdmin, admin);
3. map数据拷贝到javabean中 (注意:map的key要与javabean的属性名称一致。不一致不会报错,值为0)
BeanUtils.populate(bean, map);
4.日期类型的拷贝:
注意:对于基本数据类型,会自动进行类型转换,但日期类型则需要注册日期类型转换器,
1.自定义日期类型转换器
ConvertUtils.register(new Converter() {
// 转换的内部实现方法,需要重写
@Override
public Object convert(Class type, Object value) {
// 判断null与空字符串
if (type != Date.class) {
returnnull;
}
if (value ==null || "".equals(value.toString().trim())) {
returnnull;
}
try {
// 字符串转换为日期
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
return sdf.parse(value.toString());
} catch (ParseException e) {
thrownew RuntimeException(e);
}
}
},Date.class);
2.使用提供的日期类型转换器工具类
//注意:不能判断空字符串
ConvertUtils.register(newDateLocaleConverter(), Date.class);
DBUtils组件
commons-dbutils 是 Apache 组织提供的一个开源 JDBC工具类库,它是对JDBC的简单封装,学习成本极低,并且使用dbutils能极大简化jdbc编码的工作量,同时也不会影响程序的性能。
作用:DbUtils组件能简化jdbc操作
下载组件,引入jar文件 : commons-dbutils-1.6.jar
主要类方法:
|-- DbUtils 关闭资源、加载驱动
|-- QueryRunner 组件的核心工具类:定义了所有的与数据库操作的方法(查询、更新)
Int update(Connection conn, String sql, Object param); 执行更新带一个占位符的sql
Int update(Connection conn, String sql, Object… param); 执行更新带多个占位符的sql
Int[] batch(Connection conn, String sql, Object[][] params) 批处理
T query(Connection conn ,String sql, ResultSetHandler<T> rsh, Object... params) 查询方法
注意: 如果调用DbUtils组件的操作数据库方法没有传入连接对象,那么在实例化QueryRunner对象的时候需要传入数据源对象: QueryRunner qr = new QueryRunner(ds);
Int update( String sql, Object param);
Int update( String sql, Object… param);
Int[] batch( String sql, Object[][] params)
|-- 封装结果的一些对象:
1)BeanHandler: 查询返回单个对象
2)BeanListHandler: 查询返回list集合,集合元素是指定的对象
3) ArrayHandler, 查询返回结果记录的第一行,封装对对象数组, 即返回:Object[]
4) ArrayListHandler, 把查询的每一行都封装为对象数组,再添加到list集合中
5) ScalarHandler 查询返回结果记录的第一行的第一列 (在聚合函数统计的时候用)
6) MapHandler 查询返回结果的第一条记录封装为map
数据库连接池
原因: 连接资源宝贵,一个数据库同时支持的连接总数是有限的,如果多线程并发量很大,那么数据库连接的总数就会被消耗光,后续线程发起的数据库连接就会失败。
操作一次数据库= 创建连接, 执行操作, 关闭连接. (每个线程都会创建一次连接, 执行完后关闭)
思路:预先创建一组连接,用的时候每次取出一个,用完后放回,不断的循环使用不关闭连接
连接池(Connection集合)
全局参数:初始化连接数目,最大连接数,当前连接数,连接池集合。
构造方法:创建初始化数目的连接
获取连接:if(有连接){ 直接拿连接} else无连接{ if(达到最大连接数){ 抛出异常} else没达到{ 创建新连接 }}
释放连接:if(池中数目小于初始化数目){放入池中} else {关闭连接}
扩展:使用动态代理监测接口中方法,使用代理,可以在不实现接口的情况,对接口的方法进行扩展,添加额外的用户需要的业务逻辑!
对Connection对象,生成一个代理对象:
|--Proxy
static Object newProxyInstance(
ClassLoader loader, //当前使用的类加载器
Class<?>[] interfaces, //目标对象(Connection)实现的接口类型
InvocationHandler h //事件处理器:当执行上面接口中的方法的时候,就会自动触发事件处理器代码,把当前执行的方法(method)作为参数传入。
)
例:执行close方法时把连接放入连接池
Sun公司约定: 如果是连接池技术,需要实现一个接口!:javax.sql.DataSource;
连接池:
DBCP
C3P0
DBCP连接池:
DBCP 是 Apache 软件基金组织下的开源连接池实现,Tomcat 的连接池正是采用该连接池来实现的。该数据库连接池既可以与应用服务器整合使用,也可由应用程序独立使用。
使用DBCP数据源,应用程序应在系统中增加如下两个 jar 文件:
- Commons-dbcp.jar:连接池的实现
- Commons-pool.jar:连接池实现的依赖库
核心类:BasicDataSource
使用步骤:引入jar文件
1. 硬编码方式实现连接池
// DBCP连接池核心类
BasicDataSource dataSouce = new BasicDataSource();
// 连接池参数配置:初始化连接数、最大连接数 / 连接字符串、驱动、用户、密码
dataSouce.setUrl("jdbc:mysql:///jdbc_demo"); //数据库连接字符串
dataSouce.setDriverClassName("com.mysql.jdbc.Driver"); //数据库驱动
dataSouce.setUsername("root"); //数据库连接用户
dataSouce.setPassword("root"); //数据库连接密码
dataSouce.setInitialSize(3); // 初始化连接
dataSouce.setMaxActive(6); // 最大连接
dataSouce.setMaxIdle(3000); // 最大空闲时间
// 获取连接
Connection con = dataSouce.getConnection();
con.prepareStatement("delete from admin where id=3").executeUpdate();
// 关闭
con.close();
2. 配置方式(properties)实现连接池,便于维护【推荐】
配置文件db.properties中的key与BaseDataSouce中的属性一样
url=jdbc:mysql:///jdbc_demo
driverClassName=com.mysql.jdbc.Driver
username=root
password=123456
initialSize=3
maxActive=6
maxIdle=3000
// 加载prop配置文件
Properties prop = new Properties();
// 获取文件流
InputStream inStream = App_DBCP.class.getResourceAsStream("db.properties");
// 加载属性配置文件
prop.load(inStream);
// 根据prop配置,直接创建数据源对象
DataSource dataSouce = BasicDataSourceFactory.createDataSource(prop);
// 获取连接
Connection con = dataSouce.getConnection();
con.prepareStatement("delete from admin where id=4").executeUpdate();
// 关闭
con.close();
C3P0连接池:
最常用的连接池技术!Spring框架,默认支持C3P0连接池技术!
jar文件: c3p0-0.9.1.2.jar
核心类:CombopooledDataSource ds;
使用步骤:引入jar
1.硬编码方式
// 创建连接池核心工具类
ComboPooledDataSource dataSource = new ComboPooledDataSource();
// 设置连接参数:url、驱动、用户密码、初始连接数、最大连接数
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/jdbc_demo");
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setUser("root");
dataSource.setPassword("root");
dataSource.setInitialPoolSize(3);
dataSource.setMaxPoolSize(6);
dataSource.setMaxIdleTime(1000);
// ---> 从连接池对象中,获取连接对象
Connection con = dataSource.getConnection();
// 执行更新
con.prepareStatement("delete from admin where id=7").executeUpdate();
// 关闭
con.close();
2.配置方式(xml)
// 创建c3p0连接池核心工具类。自动加载src下c3p0的配置文件【c3p0-config.xml】
ComboPooledDataSource dataSource = new ComboPooledDataSource();// 不指定参数使用默认的配置
// 获取连接
Connection con = dataSource.getConnection();
// 执行更新
con.prepareStatement("delete from admin where id=5").executeUpdate();
// 关闭
con.close();
分页技术
JSP页面用来显示数据,如果数据有1000条,分页显示,每页显示10条,共100页; 好处: 利于页面布局,且显示的效率高!
分页关键点:
- 分页SQL语句;
- 后台处理: dao -> service -> servlet -> JSP
1.SQL语句:SELECT * FROM 表 LIMIT 从第几行起, 返回几行 ; (当前页-1)*每页显示多少条, 每页显示多少条
2.后台处理
环境准备:引入jar文件及引入配置文件
i. 数据库驱动包
ii. C3P0连接池jar文件 及 配置文件
iii. DbUtis组件: QueryRunner qr = new QueryRuner(dataSouce);
qr.update(sql);
公用类: JdbcUtils.java
1. 先设计:分页javabean:
public class PageBean{
private int currentPage; //当前页
private int pageCount; // 查询返回的行数
private int totalCount; // 总记录数
private int totalPage; // 总页数
private List pageData; // 分页查询到的数据
}2. Dao接口设计/实现: 2个方法(分页查询数据,查询总记录数)
3. Service/servlet
4. JSP