创建Connection的过程是非常耗时的,为了保证Conection可以重用。应该将Connection进行池管理
没有连接池用工厂类维护一个链接
/**
* 用静态工厂方法管理一个唯一的可重用的连接
*/
public class ConnUtils {
private static Connection con;
//在静态代码块中创建与数据库的连接
static{
try{
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql:///db909?characterEncoding=UTf8";
con = DriverManager.getConnection(url,"root","1234");
}catch(Exception e){
throw new RuntimeException(e.getMessage(),e);
}
}
//使用一个静态方法-静态工厂方法,返回connection实例
public static Connection getCon(){
return con;
}
}
mvc讲述
tomcat管理内存的方式
为了节省内存空间 每次request虽然立即死亡 但是内存确实重复使用 不销毁再构建
每个Servlet都是单例的 由tomcat维护
模拟一个用户登录的框架 mvc依次来写
表结构
create table users(
id varchar(32) primary key,
name varchar(50),
pwd varchar(32)
);
DAO层
public class RegDao {
public void reg(User user){
//声明sql语句,执行insert
Connection con = null;
try{
con = ConnUtils2.getCon();//获取连接
//声明sql
String sql = "insert into users(id,name,pwd) values(?,?,?)";
PreparedStatement pst = con.prepareStatement(sql);
pst.setString(1,user.getId());
pst.setString(2,user.getName());
pst.setString(3, user.getPwd());
pst.executeUpdate();
}catch(Exception e){
throw new RuntimeException(e.getMessage(),e);
}finally{
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
Service层
public class RegService {
//声明dao的实例,注入
private RegDao dao = new RegDao();
public void reg(User user){
//设置id
user.setId(UUID.randomUUID().toString().replace("-", ""));
//调用保存的方法
dao.reg(user);
}
}
控制层
public class RegServlet extends HttpServlet {
//声明Service4的实例
private RegService service = new RegService();
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//设置编码
request.setCharacterEncoding("UTf-8");
//接收信息
String name = request.getParameter("name");
String pwd = request.getParameter("pwd");
//封装成User对象
User u = new User(null,name,pwd);
//调用service保存
service.reg(u);
}
}
不能在dopost的方法体内new Service层的实例
但是以上方法不能多线程并发操作
注意事项
数据库表设置id主键时不要使用int 型 因为int有限度 使用varchar(32)
用java.utils.UUID类设置id
user.setId(UUID.randomUUID().toString().replace("-", ""));
String uuid = UUID.randomUUID().toString();
System.err.println(uuid + "," + uuid.length());
输出结果为 95a392c2-cee8-44e1-aadf-be15ae1fc84a,36
不需要-作为分隔符
这样写
输出结果
String uuid = UUID.randomUUID().toString().replace("-", "");
System.err.println(uuid + "," + uuid.length());
输出结果
8a72992bf7ae4d7091399507b6dee014,32
隔离级别
1:读未提交 - 一个Connection读取到了别的连接还没有提交的数据。Read uncommitted.
2:读已提交 -
3:可重复读 – 一个Connection在自己的事务之内,读取到的永远是自己之前读取到的数据。4,默认值。保证在同一个Connection的事务之内,读取到的数据,具有一侄性。
4:序列化 –Sericable – 在一个Connection操作某个表时,会对这个表执行锁定。其他的connection必须要等待解锁。
2:读已提交 -
3:可重复读 – 一个Connection在自己的事务之内,读取到的永远是自己之前读取到的数据。4,默认值。保证在同一个Connection的事务之内,读取到的数据,具有一侄性。
4:序列化 –Sericable – 在一个Connection操作某个表时,会对这个表执行锁定。其他的connection必须要等待解锁。
连接池的实现
连接池的基本实现
为什么要有连接池
1:维护多个连接。必须要保证每一个线程获取到的是不同的connection对象。
2:提供一个方法可以回收连接。
1:维护多个连接。必须要保证每一个线程获取到的是不同的connection对象。
2:提供一个方法可以回收连接。
public class ConnUtils2 {
//声明一个容器,放所有声明的连接Connection
private static List<Connection> pool = new ArrayList<Connection>();
static{
try{
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql:///db909?characterEncoding=UTf8";
for(int i=0;i<3;i++){
//创建三个连接
Connection con = DriverManager.getConnection(url,"root","1234");
//将这个三个连接放到pool中去
pool.add(con);
}
System.err.println("连接是:"+pool);
}catch(Exception e){
throw new RuntimeException(e.getMessage(),e);
}
}
public static Connection getCon(){
synchronized (pool) {
Connection con = pool.remove(0);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.err.println("还有:"+pool.size());
return con;
}
}
//手工的还连接
public static void back(Connection con){
System.err.println("还连接:"+con);
pool.add(con);
}
}
过程
声明一个缓存池。
将多个连接对象放到pool池中。
同步从池中获取一个连接。且删除已经获取出去的连接。
提供一个方法可以加收连接。
而程序员,总是调用close方法,所以为了回收连接。我们应该重写close方法。对close方法增强。
子类。
包装。
代理。