简单来讲:数据库链接池就是提供链接的。。。java
private static LinkedList<Connection> list = new LinkedList<>();
//获取链接只须要一次就够了,因此用static代码块
static {
//读取文件配置
InputStream inputStream = Demo1.class.getClassLoader().getResourceAsStream("db.properties");
Properties properties = new Properties();
try {
properties.load(inputStream);
String url = properties.getProperty("url");
String username = properties.getProperty("username");
String driver = properties.getProperty("driver");
String password = properties.getProperty("password");
//加载驱动
Class.forName(driver);
//获取多个链接,保存在LinkedList集合中
for (int i = 0; i < 10; i++) {
Connection connection = DriverManager.getConnection(url, username, password);
list.add(connection);
}
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
//重写Connection方法,用户获取链接应该从LinkedList中给他
@Override
public Connection getConnection() throws SQLException {
System.out.println(list.size());
System.out.println(list);
//先判断LinkedList是否存在链接
return list.size() > 0 ? list.removeFirst() : null;
}
复制代码
咱们已经完成前三步了,如今问题来了**。咱们调用Conncetion.close()方法,是把数据库的物理链接关掉,而不是返回给LinkedList的**mysql
解决思路:算法
分析第一个思路:sql
分析第二个思路:数据库
分析第三个思路代码实现:数组
@Override
public Connection getConnection() throws SQLException {
if (list.size() > 0) {
final Connection connection = list.removeFirst();
//看看池的大小
System.out.println(list.size());
//返回一个动态代理对象
return (Connection) Proxy.newProxyInstance(Demo1.class.getClassLoader(), connection.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//若是不是调用close方法,就按照正常的来调用
if (!method.getName().equals("close")) {
method.invoke(connection, args);
} else {
//进到这里来,说明调用的是close方法
list.add(connection);
//再看看池的大小
System.out.println(list.size());
}
return null;
}
});
}
return null;
}
复制代码
咱们上面已经可以简单编写一个线程池了。下面咱们来使用一下开源数据库链接池tomcat
使用DBCP数据源的步骤:服务器
private static DataSource dataSource = null;
static {
try {
//读取配置文件
InputStream inputStream = Demo3.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");
Properties properties = new Properties();
properties.load(inputStream);
//获取工厂对象
BasicDataSourceFactory basicDataSourceFactory = new BasicDataSourceFactory();
dataSource = basicDataSourceFactory.createDataSource(properties);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
//这里释放资源不是把数据库的物理链接释放了,是把链接归还给链接池【链接池的Connection内部本身作好了】
public static void release(Connection conn, Statement st, ResultSet rs) {
if (rs != null) {
try {
rs.close();
} catch (Exception e) {
e.printStackTrace();
}
rs = null;
}
if (st != null) {
try {
st.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
复制代码
C3P0数据源的性能更胜一筹,而且它能够使用XML配置文件配置信息!微信
步骤:oracle
private static ComboPooledDataSource comboPooledDataSource = null;
static {
//若是我什么都不指定,就是使用XML默认的配置,这里我指定的是oracle的
comboPooledDataSource = new ComboPooledDataSource("oracle");
}
public static Connection getConnection() throws SQLException {
return comboPooledDataSource.getConnection();
}
复制代码
Tomcat服务器也给咱们提供了链接池,内部其实就是DBCP
步骤:
context.xml文件的配置:
<Context>
<Resource name="jdbc/EmployeeDB"
auth="Container"
type="javax.sql.DataSource"
username="root"
password="root"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/zhongfucheng"
maxActive="8"
maxIdle="4"/>
</Context>
复制代码
try {
//初始化JNDI容器
Context initCtx = new InitialContext();
//获取到JNDI容器
Context envCtx = (Context) initCtx.lookup("java:comp/env");
//扫描以jdbc/EmployeeDB名字绑定在JNDI容器下的链接池
DataSource ds = (DataSource)
envCtx.lookup("jdbc/EmployeeDB");
Connection conn = ds.getConnection();
System.out.println(conn);
}
复制代码
dbutils它是对JDBC的简单封装,极大简化jdbc编码的工做量
提供了关闭链接,装载JDBC驱动,回滚提交事务等方法的工具类【比较少使用,由于咱们学了链接池,就应该使用链接池链接数据库】
该类简化了SQL查询,配合ResultSetHandler使用,能够完成大部分的数据库操做,重载了许多的查询,更新,批处理方法。大大减小了代码量
该接口规范了对ResultSet的操做,要对结果集进行什么操做,传入ResultSetHandler接口的实现类便可。
使用DbUtils框架对数据库的CRUD
/* * 使用DbUtils框架对数据库的CRUD * 批处理 * * */
public class Test {
@org.junit.Test public void add() throws SQLException {
//建立出QueryRunner对象
QueryRunner queryRunner = new QueryRunner(JdbcUtils.getDataSource());
String sql = "INSERT INTO student (id,name) VALUES(?,?)";
//咱们发现query()方法有的须要传入Connection对象,有的不须要传入
//区别:你传入Connection对象是须要你来销毁该Connection,你不传入,由程序帮你把Connection放回到链接池中
queryRunner.update(sql, new Object[]{"100", "zhongfucheng"});
}
@org.junit.Test public void query()throws SQLException {
//建立出QueryRunner对象
QueryRunner queryRunner = new QueryRunner(JdbcUtils.getDataSource());
String sql = "SELECT * FROM student";
List list = (List) queryRunner.query(sql, new BeanListHandler(Student.class));
System.out.println(list.size());
}
@org.junit.Test public void delete() throws SQLException {
//建立出QueryRunner对象
QueryRunner queryRunner = new QueryRunner(JdbcUtils.getDataSource());
String sql = "DELETE FROM student WHERE id='100'";
queryRunner.update(sql);
}
@org.junit.Test public void update() throws SQLException {
//建立出QueryRunner对象
QueryRunner queryRunner = new QueryRunner(JdbcUtils.getDataSource());
String sql = "UPDATE student SET name=? WHERE id=?";
queryRunner.update(sql, new Object[]{"zhongfuchengaaa", 1});
}
@org.junit.Test public void batch() throws SQLException {
//建立出QueryRunner对象
QueryRunner queryRunner = new QueryRunner(JdbcUtils.getDataSource());
String sql = "INSERT INTO student (name,id) VALUES(?,?)";
Object[][] objects = new Object[10][];
for (int i = 0; i < 10; i++) {
objects[i] = new Object[]{"aaa", i + 300};
}
queryRunner.batch(sql, objects);
}
}
复制代码
分页技术是很是常见的,在搜索引擎下搜索页面,不可能把所有数据都显示在一个页面里边。因此咱们用到了分页技术。
/* Oracle分页语法: @lineSize---每页显示数据行数 @currentPage----当前所在页 */
SELECT *FROM (
SELECT 列名,列名,ROWNUM rn
FROM 表名
WHERE ROWNUM<=(currentPage*lineSize)) temp
WHERE temp.rn>(currentPage-1)*lineSize;
复制代码
Oracle分页原理简单解释:
/* Oracle分页: Oracle的分页依赖于ROWNUM这个伪列,ROWNUM主要做用就是产生行号。 分页原理: 1:子查询查出前n行数据,ROWNUM产生前N行的行号 2:使用子查询产生ROWNUM的行号,经过外部的筛选出想要的数据 例子: 我如今规定每页显示5行数据【lineSize=5】,我要查询第2页的数据【currentPage=2】 注:【对照着语法来看】 实现: 1:子查询查出前10条数据【ROWNUM<=10】 2:外部筛选出后面5条数据【ROWNUM>5】 3:这样咱们就取到了后面5条的数据 */
复制代码
/* Mysql分页语法: @start---偏移量,不设置就是从0开始【也就是(currentPage-1)*lineSize】 @length---长度,取多少行数据 */
SELECT *
FROM 表名
LIMIT [START], length;
/* 例子: 我如今规定每页显示5行数据,我要查询第2页的数据 分析: 1:第2页的数据其实就是从第6条数据开始,取5条 实现: 1:start为5【偏移量从0开始】 2:length为5 */
复制代码
总结:
下面是常见的分页图片
配合图片,看下咱们的需求是什么:
分析:
经过上面分析,咱们会发现须要用到4个变量
//每页显示3条数据
int lineSize = 3;
//总记录数
int totalRecord = getTotalRecord();
//假设用户指定的是第2页
int currentPage = 2;
//一共有多少页
int pageCount = getPageCount(totalRecord, lineSize);
//使用什么数据库进行分页,记得要在JdbcUtils中改配置
List<Person> list = getPageData2(currentPage, lineSize);
for (Person person : list) {
System.out.println(person);
}
}
//使用JDBC链接Mysql数据库实现分页
public static List<Person> getPageData(int currentPage, int lineSize) throws SQLException {
//从哪一个位置开始取数据
int start = (currentPage - 1) * lineSize;
QueryRunner queryRunner = new QueryRunner(JdbcUtils.getDataSource());
String sql = "SELECT name,address FROM person LIMIT ?,?";
List<Person> persons = (List<Person>) queryRunner.query(sql, new BeanListHandler(Person.class), new Object[]{start, lineSize});
return persons;
}
//使用JDBC链接Oracle数据库实现分页
public static List<Person> getPageData2(int currentPage, int lineSize) throws SQLException {
//从哪一个位置开始取数据
int start = (currentPage - 1) * lineSize;
//读取前N条数据
int end = currentPage * lineSize;
QueryRunner queryRunner = new QueryRunner(JdbcUtils.getDataSource());
String sql = "SELECT " +
" name, " +
" address " +
"FROM ( " +
" SELECT " +
" name, " +
" address , " +
" ROWNUM rn " +
" FROM person " +
" WHERE ROWNUM <= ? " +
")temp WHERE temp.rn>?";
List<Person> persons = (List<Person>) queryRunner.query(sql, new BeanListHandler(Person.class), new Object[]{end, start});
return persons;
}
public static int getPageCount(int totalRecord, int lineSize) {
//简单算法
//return (totalRecord - 1) / lineSize + 1;
//此算法比较好理解,把数据代代进去就知道了。
return totalRecord % lineSize == 0 ? (totalRecord / lineSize) : (totalRecord / lineSize) + 1;
}
public static int getTotalRecord() throws SQLException {
//使用DbUtils框架查询数据库表中有多少条数据
QueryRunner queryRunner = new QueryRunner(JdbcUtils.getDataSource());
String sql = "SELECT COUNT(*) FROM person";
Object o = queryRunner.query(sql, new ScalarHandler());
String ss = o.toString();
int s = Integer.parseInt(ss);
return s;
}
复制代码
若是文章有错的地方欢迎指正,你们互相交流。习惯在微信看技术文章的同窗,能够关注微信公众号:Java3y。