自己写连接池
事先设置好多条连接存储于LinkedList中,
private static LinkedList list = new LinkedList();
for (int i = 0; i < count; i++) {
// 建立count个连接并放入连接池
list.add(DriverManager.getConnection(url, username, password));
}
每次进行增删改查直接从list取,取完之后把连接进行回收,如果每次增删改查都先建立连接,每次耗时差不多需要半秒钟,而自己写的连接池先把连接建立好储存起来,能有效的降低增删改查时的响应时间。
import java.io.FileInputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.LinkedList;
public class MyConnPoll {
private static LinkedList<Connection> list = new LinkedList<Connection>();
private static String driver;
private static String url;
private static String username;
private static String password;
/**
* 静态代码块,只在类第一次加载执行
*/
static {
try {
url = "jdbc:mysql://127.0.0.1:3306/qm?useUnicode=true&characterEncoding=utf-8";
username = "root";
password = "123";
driver = "com.mysql.jdbc.Driver";
} catch (Exception e) {
e.getStackTrace();
}
}
/**
* 使用构造函数初始化
*/
public MyConnPoll() {
try {
//注册驱动
Class.forName(driver);
initConnection(10);
} catch (Exception e) {
System.out.println("初始化连接池失败");
e.printStackTrace();
}
}
/**
* 初始化连接池
*
* @param count
* @throws SQLException
*/
public void initConnection(int count) throws SQLException {
for (int i = 0; i < count; i++) {
// 建立count个连接并放入连接池
list.add(DriverManager.getConnection(url, username, password));
}
}
/**
* 返回连接池中数量
*
* @return
*/
public int size() {
return list.size();
}
/**
* 拿到连接
* @return
* @throws SQLException
*/
public Connection getConnection() throws SQLException {
if (list.size()==0){
//如果连接用完了,再初始化一些连接出来
initConnection(10);
}
//list是链表,每次返回list的第一个连接
return list.removeFirst();
}
/**
* 使用代理模式修改conn对象的close方法
*
* @return
* @throws SQLException
*/
/* public Connection getConnection() throws SQLException {
if (list.size()==0){
initConnection(10);
}
final Connection conn=list.removeFirst();
//代理模式
return (Connection) Proxy.newProxyInstance(MyConnPoll.class.getClassLoader(),
new Class[]{Connection.class},
new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (!"close".equals(method.getName())){
return method.invoke(conn,args);
}else {
closeConnection(conn);
System.out.println("回收了一个连接,当前连接数是:"+size());
return null;
}
}
});
}
*/
/**
* 用完回收连接
*
* @param conn
*/
public void closeConnection(Connection conn) {
list.add(conn);
}
}
SQL注入
使用
Statement statement = conn.createStatement();
statement.executeQuery(“select * from user where username=’+username+’ “);时
当username的值为 ’ or 1=1 - 时,sql语句查询时会变成
select * from user where username=’’ or 1=1 -’
这条语句被拆分开来,
即username=’’
1=1 永久成立
-’ 这是把后面的全部注释掉
即便表里没有这个值,它的查询也是成功的。注入此类还有很多,比如加入分号;把前面的语句断掉,后面再加新语句。
解决办法是当用户输入时,把一些特殊字符给替换掉,比如:
String name = scanner.nextLine();
String replace = name.replace(”’”,"\’");
但更有效的解决方法是不使用Statement,而是使用
String sql = "SELECT * FROM maillist where name like ? ";
//创建运行对象
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1,mailList.getName());
去代替Statement,PreparedStatement是基于Statement的,
但在SQL语句中使用问号?去代替拼接的SQL,这样能提高程序的安全性。
且PreparedStatement有预编译的过程,已经绑定sql,之后无论执行多少遍,都不会再去进行编译,
而 statement 不同,如果执行多少遍,则相应的就要编译多少遍sql,所以从这点看,preStatement 的效率会比 Statement要高一些。
Druid
Druid是Java语言中最好的数据库连接池。Druid能够提供强大的监控和扩展功能。
Maven:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.22</version>
</dependency>
一个连接池框架,能省去许多繁琐的东西。
Druid工具类:
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
public class JDBCUtils {
private static DataSource dataSource = null;
static {
try {
/*创建一个与src同级的目录,config,在其下创建一个properties类型文件
文件中存放driverClassName这里使用的不是driver
username、password、url
然后用load加载进来。
甚至在关闭连接时
JDBCUtils.close();并不是直接关闭,而是回收。
*/
Properties p = new Properties();
p.load(JDBCUtils.class.getClassLoader().getResourceAsStream("config/druid.properties"));
//工厂对象
DruidDataSourceFactory druidDataSourceFactory = new DruidDataSourceFactory();
dataSource = druidDataSourceFactory.createDataSource(p);
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException {
//连接
return dataSource.getConnection();
}
public static void close(Connection connection, Statement statement, ResultSet resultSet) {
// 代码的严谨性
try {
if (resultSet != null) {
resultSet.close();
}
} catch (Exception e) {
e.printStackTrace();
}
try {
if (statement != null) {
statement.close();
}
} catch (Exception e) {
e.printStackTrace();
}
try {
if (connection != null) {
connection.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
druid.properties文件中:
driverClassName=com.jdbc.mysql.
url=jdbc:mysql://127.0.0.1:3306/qm
username=root
password=123
#初始化连接数
initialSize=5
#最多连接数
maxActive=10
#...还有更多属性
使用Druid可以省略很多东西,方便开发,更深层次的目前还没掌握。