- 浏览: 53409 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
01404421:
正在学习,谢谢LZ分享了,提出个小意见,当使用连接池的程序在关 ...
java连接池浅谈 -
foolfisher:
收了
java连接池浅谈 -
qiancaoduwu:
循环是不是没有写完?
完整的连接池类 -
realorg:
顺便说说,怎么解密~◎
谢谢
java的md5加密类 -
realorg:
那个好像不叫内部类哦~!
:)
完整的连接池类
Oracle连接池需要odbc连接包
1。读取配置文件
db.properties
drivers=oracle.jdbc.driver.OracleDriver
r2gdb.url=jdbc:oracle:thin:@192.168.1.16:1521:r2gdb
r2gdb.user=boss2
r2gdb.password=boss2
r2gdb.maxConns=100
r2gdb.minConns=2
r2gdb.logInterval=60000
r2gdb_boss.url=jdbc:oracle:thin:@192.168.1.16:1521:r2gdb
r2gdb_boss.user=billing
r2gdb_boss.password=billing
r2gdb_boss.maxConns=100
r2gdb_boss.minConns=2
r2gdb_boss.logInterval=60000
2.连接池类
package com.database;
import java.io.*;
import java.sql.*;
import java.util.*;
import java.util.Date;
public class DBConnectionManager
{
static private DBConnectionManager instance; // 唯一实例
static private int clients;
private Vector drivers = new Vector();
private PrintWriter log;
private Hashtable pools = new Hashtable();
/**
* 返回唯一实例.如果是第一次调用此方法,则创建实例
*
* @return DBConnectionManager 唯一实例
*/
static synchronized public DBConnectionManager getInstance()
{
if (instance == null)
{
instance = new DBConnectionManager();
}
clients++;
return instance;
}
/**
* 建构函数私有以防止其它对象创建本类实例
*/
private DBConnectionManager()
{
init();
}
/**
* 将连接对象返回给由名字指定的连接池
*
* @param name 在属性文件中定义的连接池名字
* @param con 连接对象
*/
public void freeConnection(String name, Connection con)
{
DBConnectionPool pool = (DBConnectionPool) pools.get(name);
if (pool != null)
{
pool.freeConnection(con);
//log("连接反池");
}
}
/**
* 获得一个可用的(空闲的)连接.如果没有可用连接,且已有连接数小于最大连接数
* 限制,则创建并返回新连接
*
* @param name 在属性文件中定义的连接池名字
* @return Connection 可用连接或null
*/
public Connection getConnection(String name)
{
DBConnectionPool pool = (DBConnectionPool) pools.get(name);
if (pool != null)
{
return pool.getConnection();
}
return null;
}
/**
* 获得一个可用连接.若没有可用连接,且已有连接数小于最大连接数限制,
* 则创建并返回新连接.否则,在指定的时间内等待其它线程释放连接.
*
* @param name 连接池名字
* @param time 以毫秒计的等待时间
* @return Connection 可用连接或null
*/
public Connection getConnection(String name, long time)
{
DBConnectionPool pool = (DBConnectionPool) pools.get(name);
if (pool != null)
{
return pool.getConnection(time);
}
return null;
}
/**
* 关闭所有连接,撤销驱动程序的注册
*/
public synchronized void release()
{
// 等待直到最后一个客户程序调用
if (--clients != 0)
{
return;
}
Enumeration allPools = pools.elements();
while (allPools.hasMoreElements())
{
DBConnectionPool pool = (DBConnectionPool) allPools.nextElement();
pool.release();
}
Enumeration allDrivers = drivers.elements();
while (allDrivers.hasMoreElements())
{
Driver driver = (Driver) allDrivers.nextElement();
try
{
DriverManager.deregisterDriver(driver);
//log("撤销JDBC驱动程序 " + driver.getClass().getName() + "的注册");
}
catch (SQLException e)
{
//log(e, "无法撤销下列JDBC驱动程序的注册: " + driver.getClass().getName());
}
}
}
/**
* 根据指定属性创建连接池实例.
*
*
<poolname></poolname>
.url The JDBC URL for the database
*
<poolname></poolname>
.user A database user (optional)
*
<poolname></poolname>
.password A database user password (if user specified)
*
<poolname></poolname>
.maxconn The maximal number of connections (optional)
*
* @param props 连接池属性
*/
private void createPools(Properties props)
{
Enumeration propNames = props.propertyNames();
while (propNames.hasMoreElements())
{
String name = (String) propNames.nextElement();
if (name.endsWith(".url"))
{
String poolName = name.substring(0, name.lastIndexOf("."));
String url = props.getProperty(poolName + ".url");
if (url == null)
{
//log("没有为连接池" + poolName + "指定URL");
continue;
}
String user = props.getProperty(poolName + ".user");
String password = props.getProperty(poolName + ".password");
String maxconn = props.getProperty(poolName + ".maxConns", "0");
String minconn = props.getProperty(poolName + ".minConns", "0");
//System.out.println(maxconn);
//System.out.println(minconn);
int max, min;
long logInterval =500;
try
{
max = Integer.valueOf(maxconn).intValue();
min = Integer.valueOf(minconn).intValue();
}
catch (NumberFormatException e)
{
//log("错误的最大连接数限制: " + maxconn + " .连接池: " + poolName);
//log("错误的连接数限制: " + minconn + " .连接池: " + poolName);
max = 0;
min = 0;
}
DBConnectionPool pool =
new DBConnectionPool(poolName, url, user, password, max, min,logInterval);
pools.put(poolName, pool);
//log("成功创建连接池" + poolName);
}
}
}
/**
* 读取属性完成初始化
*/
private void init()
{
InputStream is = getClass().getResourceAsStream("db.properties");
Properties dbProps = new Properties();
try
{
dbProps.load(is);
}
catch (Exception e)
{
System.err.println("不能读取属性文件. " +
"请确保db.properties在CLASSPATH指定的路径中");
return;
}
String path=getClass().getResource("/").getPath();
String datapath=path+"com/database/DBConnectionManager.log";
//datapath=datapath.substring(1,datapath.length());
String logFile = dbProps.getProperty("logfile",datapath);
try
{
log = new PrintWriter(new FileWriter(logFile, true), true);
}
catch (IOException e)
{
//System.err.println("无法打开日志文件: " + logFile);
//log = new PrintWriter(System.err);
}
loadDrivers(dbProps);
createPools(dbProps);
}
/**
* 装载和注册所有JDBC驱动程序
*
* @param props 属性
*/
private void loadDrivers(Properties props)
{
String driverClasses = props.getProperty("drivers");
StringTokenizer st = new StringTokenizer(driverClasses);
while (st.hasMoreElements())
{
String driverClassName = st.nextToken().trim();
try
{
Driver driver = (Driver)
Class.forName(driverClassName).newInstance();
DriverManager.registerDriver(driver);
drivers.addElement(driver);
//log("成功注册JDBC驱动程序" + driverClassName);
}
catch (Exception e)
{
//log("无法注册JDBC驱动程序: " +
//driverClassName + ", 错误: " + e);
}
}
}
/**
* 将文本信息写入日志文件
*/
private void log(String msg)
{
log.println(new Date() + ": " + msg);
}
/**
* 将文本信息与异常写入日志文件
*/
private void log(Throwable e, String msg)
{
log.println(new Date() + ": " + msg);
e.printStackTrace(log);
}
/**
* 此内部类定义了一个连接池.它能够根据要求创建新连接,直到预定的最
* 大连接数为止.在返回连接给客户程序之前,它能够验证连接的有效性.
*/
class DBConnectionPool
{
private final int SLEEP_INTERVAL = 10000;
private int checkedOut;
private Vector freeConnections = new Vector();
private int maxConn;
private int minConn;
private String name;
private String password;
private String URL;
private String user;
private long logTimer;
private long logInterval;
private long lastUsedTime;
private Thread poolMonitor;
/**
* 创建新的连接池
*
* @param name 连接池名字
* @param URL 数据库的JDBC URL
* @param user 数据库帐号,或 null
* @param password 密码,或 null
* @param maxConn 此连接池允许建立的最大连接数
* 每个连接池始终保持一定数量的连接.当申请连接时如果连接池中连接数小于定值
* 则申请新的连接
* 连接池设置监控线程每个一段时间就扫描池中的连接如果不可用则删除之并记录连接池的状态
*/
public DBConnectionPool(String name, String URL, String user,
String password,
int maxConn, int minConn, long logInterval)
{
this.name = name;
this.URL = URL;
this.user = user;
this.password = password;
this.maxConn = maxConn;
this.minConn = minConn;
this.logInterval = logInterval;
for (int i = 0; i {
Connection initConn = newConnection();
freeConnections.addElement(initConn);
}
lastUsedTime=System.currentTimeMillis();
logTimer = System.currentTimeMillis();
poolMonitor = new Thread (new Runnable()
{
public void run()
{
monitor();
}
}
);
poolMonitor.start();
} /* end constructor*/
private void monitor()
{
while ( true )
{
///每隔logInterval对连接池清理一次,删除无效连接,后者在很长一段时间没有使用的连接
if ( (System.currentTimeMillis() - logTimer) > logInterval)
{
Enumeration checkconn = freeConnections.elements();
while (checkconn.hasMoreElements())
{
Connection con = (Connection) checkconn.nextElement();
try
{
if(con == null || con.isClosed() || (System.currentTimeMillis()-lastUsedTime>12000))
{
con.close();
freeConnections.removeElement(con);
//log("关闭连接池" + name + "中的一个连接");
}
}
catch(SQLException e)
{
System.out.println("momitor 出错!");
}
}
while (freeConnections.size() < minConn)
{
Connection con = newConnection();
freeConnections.addElement(con);
}
logTimer = System.currentTimeMillis();
}
try
{
Thread.sleep(SLEEP_INTERVAL);
}
catch (InterruptedException e)
{
System.out.println("监控线程被打断!!");
}
}//end while
}
/**
* 将不再使用的连接返回给连接池
*
* @param con 客户程序释放的连接
*/
public synchronized void freeConnection(Connection con)
{
// 将指定连接加入到向量末尾
freeConnections.addElement(con);
try
{
con.close();
}catch(Exception e){}
checkedOut--;
notifyAll();
}
/**
* 从连接池获得一个可用连接.如没有空闲的连接且当前连接数小于最大连接
* 数限制,则创建新连接.如原来登记为可用的连接不再有效,则从向量删除之,
* 然后递归调用自己以尝试新的可用连接.
*/
public synchronized Connection getConnection()
{
Connection con = null;
if (freeConnections.size() > 0)
{
// 获取向量中第一个可用连接
con = (Connection) freeConnections.firstElement();
freeConnections.removeElementAt(0);
try
{
if (con.isClosed()||con==null||(System.currentTimeMillis()-lastUsedTime>12000))
{
//log("从连接池" + name + "删除一个无效连接");
// 递归调用自己,尝试再次获取可用连接
con.close();
con = getConnection();
}
}
catch (SQLException e)
{
//log("从连接池" + name + "删除一个无效连接");
// 递归调用自己,尝试再次获取可用连接
con = getConnection();
}
}
else if (maxConn == 0 || freeConnections.size() < maxConn)
{
con = newConnection();
}
return con;
}
/**
* 从连接池获取可用连接.可以指定客户程序能够等待的最长时间
* 参见前一个getConnection()方法.
*
* @param timeout 以毫秒计的等待时间限制
*/
public synchronized Connection getConnection(long timeout)
{
long startTime = new Date().getTime();
Connection con;
while ( (con = getConnection()) == null)
{
try
{
wait(timeout);
}
catch (InterruptedException e)
{}
if ( (new Date().getTime() - startTime) >= timeout)
{
// wait()返回的原因是超时
return null;
}
}
return con;
}
/**
* 关闭所有连接
*/
public synchronized void release()
{
Enumeration allConnections = freeConnections.elements();
while (allConnections.hasMoreElements())
{
Connection con = (Connection) allConnections.nextElement();
try
{
con.close();
//log("关闭连接池" + name + "中的一个连接");
}
catch (SQLException e)
{
// log(e, "无法关闭连接池" + name + "中的连接");
}
}
freeConnections.removeAllElements();
}
/**
* 创建新的连接
*/
private Connection newConnection()
{
Connection con = null;
try
{
if (user == null)
{
con = DriverManager.getConnection(URL);
}
else
{
con = DriverManager.getConnection(URL, user, password);
}
//log("连接池" + name + "创建一个新的连接");
}
catch (SQLException e)
{
//log(e, "无法创建下列URL的连接: " + URL);
return null;
}
return con;
}
}
}
3。连接池管理类
package com.database;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.ParseException;
import java.text.SimpleDateFormat;
public class DBConn {
private Connection conn = null;
private Statement stmt = null;
private PreparedStatement prepstmt = null;
private DBConnectionManager dcm = null;
private ResultSet rs = null;
private String connName = null;
// 初始化
void init() {
dcm = DBConnectionManager.getInstance();
conn = dcm.getConnection(connName);
while (conn == null) {
conn = dcm.getConnection(connName, 10);
}
}
// 设置连接
public void setConnName(String connName) throws Exception {
this.connName = connName;
init();
stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE);
}
// 构造数据库的连接和访问类
public DBConn() throws Exception {
// init();
// stmt = conn.createStatement();
}
/*
* public DBconn(String connName) throws Exception { this.connName =
* connName; init(); stmt = conn.createStatement(); }
*/
public DBConn(int resultSetType, int resultSetConcurrency) throws Exception {
init();
stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE);
}
/**
* 构造数据库的连接和访问类 预编译SQL语句
*
* @param sql
* SQL语句
*/
public DBConn(String sql) throws Exception {
init();
this.prepareStatement(sql);
}
public DBConn(String sql, int resultSetType, int resultSetConcurrency)
throws Exception {
init();
this.prepareStatement(sql, resultSetType, resultSetConcurrency);
}
/**
* 返回连接
*/
public Connection getConnection() {
return conn;
}
/**
* 返回预设状态
*/
public PreparedStatement getPreparedStatement() {
return prepstmt;
}
/**
* 返回状态
*/
public Statement getStatement() {
return stmt;
}
/**
* 预设SQL语句
*/
public void prepareStatement(String sql) throws SQLException {
prepstmt = conn.prepareStatement(sql);
}
public void prepareStatement(String sql, int resultSetType,
int resultSetConcurrency) throws SQLException {
prepstmt = conn.prepareStatement(sql, resultSetType,
resultSetConcurrency);
}
// *中文转码操作
public String codingStr(String str) {
try {
byte[] temp = str.getBytes("GBK");
str = new String(temp, "iso8859_1");
} catch (Exception e) {
System.out.println(e);
}
return str;
}
public String to_GBK(String str) {
try {
byte[] temp = str.getBytes("iso8859_1");
str = new String(temp, "GBK");
} catch (Exception e) {
System.out.println(e);
}
return str;
}
/**
* 设置对应值
*
* @param index
* 参数索引
* @param value
* 对应值
*/
public void setString(int index, String value) throws SQLException {
prepstmt.setString(index, value);
}
public void setInt(int index, int value) throws SQLException {
prepstmt.setInt(index, value);
}
public void setBoolean(int index, boolean value) throws SQLException {
prepstmt.setBoolean(index, value);
}
public void setDate(int index, Date value) throws SQLException {
prepstmt.setDate(index, value);
}
public void setLong(int index, long value) throws SQLException {
prepstmt.setLong(index, value);
}
public void setFloat(int index, float value) throws SQLException {
prepstmt.setFloat(index, value);
}
public void setBytes(int index, byte[] value) throws SQLException {
prepstmt.setBytes(index, value);
}
public void clearParameters() throws SQLException {
prepstmt.clearParameters();
prepstmt = null;
}
public void commit() throws SQLException {
conn.commit();
}
public void rollback() throws SQLException {
conn.rollback(); // 操作不成功则回滚
}
public void setAutoCommit(boolean str) throws SQLException {
conn.setAutoCommit(str);
}
/**
* 执行SQL语句返回字段集(用于查找)
*
* @param sql
* SQL语句
* @return ResultSet 字段集
*/
public ResultSet executeQuery(String sql) throws SQLException {
if (stmt != null) {
return stmt.executeQuery(sql);
} else {
return null;
}
}
public ResultSet executeQuery() throws SQLException {
if (prepstmt != null) {
return prepstmt.executeQuery();
} else {
return null;
}
}
/**
* 执行SQL语句(用于更新、插入、删除)
*
* @param sql
* SQL语句
*/
public void executeUpdate(String sql) throws SQLException {
if (stmt != null) {
stmt.executeUpdate(sql);
}
}
public void executeUpdate() throws SQLException {
if (prepstmt != null) {
prepstmt.executeUpdate();
}
}
public CallableStatement prepareCall(String sqlStmt) throws SQLException {
return conn.prepareCall(sqlStmt);
}
/*
* 执行所有SQL语句
*/
public int execSQL(String sqlStmt) throws SQLException {
if (conn == null) {
init();
}
if (stmt == null) {
stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE);
}
if (sqlStmt.toUpperCase().startsWith("SELECT")) {
rs = stmt.executeQuery(sqlStmt);
return -1;
} else {
conn.setAutoCommit(true);
int numRow = stmt.executeUpdate(sqlStmt);
return numRow;
}
}
public int execSQL_file(String sqlStmt) throws SQLException {
if (conn == null) {
init();
}
if (stmt == null) {
stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE);
}
if (sqlStmt.toUpperCase().startsWith("SELECT")) {
rs = stmt.executeQuery(sqlStmt);
return -1;
} else {
conn.setAutoCommit(false);
int numRow = stmt.executeUpdate(sqlStmt);
return numRow;
}
}
// 使用字段名获取
public String getString(String fieldName) throws SQLException {
if (rs.getString(fieldName) == null
|| rs.getString(fieldName).equals("null"))
return "";
else
return rs.getString(fieldName);
}
// 使用字段索引获取
public String getString(int fieldNo) throws SQLException {
return rs.getString(fieldNo);
}
public int getInt(String fieldName) throws SQLException {
return rs.getInt(fieldName);
}
public int getInt(int fieldNo) throws SQLException {
return rs.getInt(fieldNo);
}
public float getFloat(int fieldNo) throws SQLException {
return rs.getFloat(fieldNo);
}
public float getFloat(String fieldName) throws SQLException {
return rs.getFloat(fieldName);
}
public Date getDate(int fieldNo) throws SQLException {
return rs.getDate(fieldNo);
}
public Date getDate(String fieldName) throws SQLException {
return rs.getDate(fieldName);
}
// 指向第一条的前端(初始位置)
public void beforeFirst() throws SQLException {
rs.beforeFirst();
}
// 返回是否指向第一条的前端(初始位置)
public boolean isBeforeFirst() throws SQLException {
return rs.isBeforeFirst();
}
// 指向第一条记录
public boolean first() throws SQLException {
return rs.first();
}
// 返回是否第一条记录
public boolean isFirst() throws SQLException {
return rs.isFirst();
}
// 向前移动一条
public boolean previous() throws SQLException {
if (rs == null) {
throw new SQLException("Resultset is null!");
}
return rs.previous();
}
// 指向下一条记录
public boolean next() throws SQLException {
return rs.next();
}
// 返回是否存在下一条记录
public boolean hasNext(String sql) throws SQLException {
boolean isnext = false;
execSQL(sql);
if (rs.next()) {
isnext = true;
}
return isnext;
}
// 指向最后一条记录
public boolean last() throws SQLException {
return rs.last();
}
// 返回是否指向最后一条记录
public boolean isLast() throws SQLException {
return rs.isLast();
}
// 指向指定的第row行记录
public boolean absolute(int Row) throws SQLException {
return rs.absolute(Row);
}
// 指向最后一条的下一条记录
public void afterLast() throws SQLException {
rs.afterLast();
}
// 返回是否指向最后一条记录的下一条记录
public boolean isAfterLast() throws SQLException {
return rs.isAfterLast();
}
/** ****** relative ******* */
public boolean relative(int row) throws SQLException {
return rs.relative(row);
}
// 返回指向的记录是第几条
public int getRow() throws SQLException {
return rs.getRow();
}
// 返回一共有多少条记录
public int getRows() throws SQLException {
rs.last();
int rows = rs.getRow();
rs.beforeFirst();
return rows;
}
/**
* 关闭连接
*/
public void close() throws Exception {
if (stmt != null) {
stmt.close();
stmt = null;
}
if (prepstmt != null) {
prepstmt.close();
prepstmt = null;
}
if (conn != null) {
dcm.freeConnection(connName, conn);
}
}
/*测试
* public static void main(String[] args) throws Exception { DBConn dbConn =
* new DBConn(); dbConn.setConnName("backup"); System.out.println("dd"); }
*/
}
相关推荐
自己实现的ActiveMQ连接池和新版本ActiveMQ自带的连接池,封装好的工具类,可直接使用,自己在网上找的时候好多都是纯Demo性质的,没有好的思想可以学习,希望我的劳动成果可以供你学习借鉴
该文章把数据库连接池的内部原理写的非常透彻,注释也非常完整,是非常难得的一篇好文章,让开发人员可以更深层次的理解数据库连接池。该文件对可以设置连接池的初始大小、连接池自动增加的大小、 连接池最大的大小...
使用apache的commons-pool2 构建 FTPClient连接池 有FtpClientFactory、FtpClientPool、FtpConfig、FtpOperate 四个类组成 还有ftp连接池的一些配置参数信息在ftp.properties文件中 注释完整欢迎大家下载使用
下载下来即可导入本地运行 手写连接池经典实例 包含实例所用的若干jar文件 和包含各种驱动配置文件 主要类: DBConnectionManager.java DBConnectionPool.java PoolTest.java
这个数据库连接池的实现,包含了源代码,从配置文件读取驱动等相关信息支持Oracle和sql server等多种数据库,里面有写好的测试类
Java动态代理实现数据源连接池,用代理类实现的连接池代码,绝对完整的案例,下载源码就能跑起来!Java动态代理实现数据源连接池,用代理类实现的连接池代码
使用Java写的连接池 完整版, 带有测试类
driveClassName:JDBC驱动类的完整的名称; maxActive:同时能够从连接池中被分配的可用实例的最大数; maxIdle:可以同时闲置在连接池中的连接的最大数; maxWait:最大超时时间,以毫秒计; password:用户...
本资源是一个S2SH架构整合的一个完整例子,包含:struts2的完整配置及实例,使用c3p0连接池,Spring的事务管理、类路径扫描管理功能、注解功能。例子本人已测试通过,所有配置和代码都有完整的注释,适合初学者或者...
显示数据库中的表用java(完整)- - *该程序代码用到了前面说的database.java的数据库连接池的类
技术选型 1、后端 核心框架:Spring Boot 安全框架:Apache Shiro 模板引擎:Thymeleaf 持久层框架:MyBatis 数据库连接池:Alibaba Druid 缓存框架:Ehcache 、Redis 日志管理:SLF4J 工具类:Apache Commons、...
技术选型 1、后端 核心框架:Spring Boot 安全框架:Apache Shiro 模板引擎:Thymeleaf 持久层框架:MyBatis 数据库连接池:Alibaba Druid 缓存框架:Ehcache 、Redis 日志管理:SLF4J 工具类:Apache Commons、...
java部分:程序基本概念、数据类型、流程控制、顺序、选择 、循环、跳转语句、变量、类、方法、实用类、JDBC、三层架构Druid连接池、Apache的DBUtils使用、Servlet等。 数据库部分:创建表、增删改查语句的书写等。 ...
● 屏蔽Jedis与JedisCluster的连接细节和差异,统一封装成RedisClient类,并内置连接池 ● 统一Jedis与JedisCluster连接的配置项,封装成RedisBean类,主要供RedisClient使用 ● 屏蔽byte[]数据类型,所有实现了序列...
发布CXF+Spring整合的REST的服务接口完整实例,其中包括数据库连接池,json数据格式传递数据,HttpURLConne的get和post方式调用接口,以及获取访问者ip地址工具类等众多的技术实例。
数据库连接池:Alibaba Druid 缓存框架:Ehcache 、Redis 日志管理:SLF4J 工具类:Apache Commons、Jackson 2、前端 JS框架:jQuery 客户端验证:JQuery Validation 富文本在线编辑:summernote 数据表格:...
> 使用SpringBoot 集成Spring-data-jpa,Druid连接池,thymeleaf模板实现的一个简单网上商城项目,包含后台管理 简单的网上商城系统,基于springboot,后台实现了商品分类,商品管理,订单管理,订单发货,订单详情,...
权限管理: 用户管理、部门管理、岗位管理、菜单管理、角色管理、字典和参数管理等 系统监控: 操作日志、登录日志、系统日志、在线用户、服务监控、连接池监控、缓存监控等 产品管理: 产品、产品物模型、产品分类...
基于Java springboot+mybatis+mysql实现的校园新闻系统(高分毕设)已获导师指导并通过的...数据库:MySQL,Druid 连接池。 其他:Maven、Thymeleaf 详情:https://blog.csdn.net/qq_33037637/article/details/124886258
第34节实战:简易数据连接池00:24:53分钟 | 第35节线程之间通信之join应用与实现原理剖析00:10:17分钟 | 第36节ThreadLocal 使用及实现原理00:17:41分钟 | 第37节并发工具类CountDownLatch详解00:22:04分钟 | 第...