声明:本博客所有文章都是原创,不会有任何抄袭现象。请转载的朋友,标注出处,谢谢。
最近比较流行springboot微服务,那么持久层到底怎么样才算好?面对高并发的压力,如何抵制?本文将以JDBC来讲解敏捷开发,抵制高并发。本文为正在使用springboot的朋友提供帮助。对于零经验的朋友们,建议先学习下springboot的相关知识,然后再看这篇文章。
说到JDBC,我们第一件事是什么?先导入jar包对不对。JDK啥的一些基础包我就不多说了,下图是mysql的驱动包。
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
下面要说的是代码应该如何写,怎么写?如何优,怎么优的问题。大部分初学者,都会写个static的Connection然后再释放连接。殊不知开关连接是最消耗资源的,就像创建线程一样。那我们有没有什么办法让连接从始至终只实例一次呢?答案肯定是有的。先附上dbcp的maven包
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
</dependency>
public class JdbcUtils {
private static final ThreadLocal<Connection> CONNECTION_HOLDER;
private static final BasicDataSource DATA_SOURCE = new BasicDataSource();
private JdbcUtils() {
}
static {
CONNECTION_HOLDER = new ThreadLocal<Connection>();
Properties conf = loadProps("dbconfig.properties");
String driverClass = conf.getProperty("jdbc.driverClass");
String url = conf.getProperty("jdbc.url");
String username = conf.getProperty("jdbc.username");
String password = conf.getProperty("jdbc.password");
DATA_SOURCE.setDriverClassName(driverClass);
DATA_SOURCE.setUrl(url);
DATA_SOURCE.setUsername(username);
DATA_SOURCE.setPassword(password);
}
注意:提到两个东西,ThreadLocal和BasicDataSource。Threadlocal看上去像是本地线程的意思,我认为更好的词汇应该是本地变量。它会给每个访问的线程一个自己的实例,不存在线程阻塞的状况,我认为它也可以叫异步处理,因为我喜欢使用它进行异步编程。BasicDataSource翻译就是基本的数据源,没错,它就是连接池。
其实你可以把他们看作是线程池和连接池,用来管理数据的操作,这就是上面提到的,是实例一次的解决办法。我把连接的配置写在properties的文件里,然后和大家一样用流读取配置,把配置信息交给连接池来管理。有人似乎看到一行代码是这样写的:
try(){
}catch(Exception e){}
初学者甚至前辈也会问,try后面可以加括号?你耍我呢吧?答案是确实可以,这是JDK7的功能,但并不是什么都可以往里写,它的功能是自己帮你关闭连接,哪些连接呢?我们看下源码
。没错,只能关闭那些实现了Closeable接口的类。那么你还用不用手动关闭了?当然不用了。朋友说,你快别扯犊子了,赶紧说吧。说说怎么用吧,太墨迹了。
private static Connection getConnection() {
Connection conn = CONNECTION_HOLDER.get();
if (conn == null) {
try {
conn = DATA_SOURCE.getConnection();
} catch (Exception e) {
e.printStackTrace();
} finally {
CONNECTION_HOLDER.set(conn);
}
}
return conn;
}
//资源的释放
private static void release(Connection conn, PreparedStatement st,ResultSet rs) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
rs = null;
}
}
if (st != null) {
try {
st.close();
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
st = null;
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
conn = null;
}
}
}
注意:释放连接,并没有真正的关闭,只是把连接放回连接池里而已。
附上一个公用的查询方法,返回List里面包的Map集合。
/**
* @author PQF
* @category 根据SQL进行查询返回一个List实体集合
* @param 1.传送一个查询的sql语句
* @param 2.sql中使用占位符(?)所对应的实际值
* @param 3.你要查询的列
* @throws Exception
*/
public static List<Map<String, String>> queryEntityList(String sql,
List<String> list, String[] column) throws Exception {
List<Map<String, String>> entityList = new ArrayList<>();
if (sql.isEmpty() || column.length < 1) {
throw new Exception("SQL语句不能为空,并且列的长度不能小于1");
}
Connection conn = getConnection();
PreparedStatement prepareStatement = null;
ResultSet result = null;
try {
prepareStatement = conn.prepareStatement(sql.toString());
if(BaseUtil.ObjectNotNull(list)){
for (int i = 1; i <= list.size(); i++) {
prepareStatement.setString(i, list.get(i-1));
}
}
result = prepareStatement.executeQuery();
Map<String, String> mapList = null;
while (result.next()) {
mapList = new HashMap<>();
for (Object col : column) {
mapList.put((String) col, result.getString((String) col));
}
entityList.add(mapList);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
release(conn, prepareStatement, result);
}
return entityList;
}
public static boolean ObjectNotNull(Object object){
return object != null && !"".equals(object) && !object.equals("null") ? true : false;
}
至此,就可以了。亲测50并发毫无压力,2000并发只需1秒多搞定。是不是很给力,觉得还行就点个赞吧,让更多的人一起分享。
这是我写的第4篇文章,愿我微不足道的力量与您一同成长。