springboot手写JDBC面对2000并发量毫无压力

  • Post author:
  • Post category:其他


声明:本博客所有文章都是原创,不会有任何抄袭现象。请转载的朋友,标注出处,谢谢。



最近比较流行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篇文章,愿我微不足道的力量与您一同成长。



版权声明:本文为u011550710原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。