gkbmnkgnbkgfnjnkjbnkjn关于数据库连接jdbc
mysql权限不足如何处理
-
execute 执行任意sql,不能获取数据库的结果,返回boolean表示查询是否有结果
-
executeUpdate 执行insert、delete、update,返回值int,表示当前sql影响 数据库表的行计数
-
executeQuery 主要执行select查询语句,返回ResultSet结果集,结果集中就是查询到数据
jdbc经过封装构建成-->ORM映射框架Mybatis,Hibernate(写注解,自动生成)
public class SqlTest{
public static void insert(){
//1.注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//请求资源定位符,协议://ip:port/database
String url = "jdbc:mysql://192.168.174.136:3306/gather";
//2、获取连接 DriverManager驱动管理类
Connection conn =
DriverManager.getConnection(
url, "root", "root");
//3、创建Statement对象效率没有后者高或者PreparedStatement对象
Statement sts = conn.createStatement();
//4、执行sql语句
//4、执行sql语句 "insert into student " +字符串拼接时注意空格
boolean b = sts.execute("insert into student " +
"values(1,'lisi',30,'2024-09-22 10:22:30')");
System.out.println(b);
//5、执行的sql有结果返回处理结果,没有结果执行第6步
//6、关闭资源,正开倒关
if (sts != null) sts.close();//statement对象资源
if (conn != null) conn.close();
}
public static void main(String[] args){
insert();
}
}
1、时间对象都有getTime()方法,获取时间戳对象
2、时间对象构建的时候参数可以传入时间戳
public static void date_test() {
/*
java.util.Date
java.sql.Date
java.sql.TimeStamp
时间之间的转化都是基于时间戳
*/
Date date = new Date();
//java.util.Date获取时间对象的时间戳
long t = date.getTime();
//java.util.Date转化为java.sql.Date、java.sql.TimeStamp
java.sql.Date date1 = new java.sql.Date(t);
//java.sql.Date获取时间对象的时间戳
long t1 = date1.getTime();
//将java.sql.Date转化为java.util.Date、java.sql.TimeStamp
Date date3 = new Date(t1);
Timestamp date4 = new Timestamp(t1);
Timestamp date2 = new Timestamp(t);
//获取java.sql下时间戳
long t3 = date2.getTime();
System.out.println(date1);
System.out.println(date2);
}
ctrl点进去就是官方文档
public static void str_date() throws ParseException {
//参数是时间呈现格式的字符串模版
SimpleDateFormat sdf =
new SimpleDateFormat(
"yyyy-MM-dd hh:mm:ss.SSS");
//获取当前时间对象java.util.Date
Date date = new Date();
//将时间对象转化为特定格式的字符串
String str = sdf.format(date);
System.out.println(str);
//时间的字符串,要求必须和SimpleDateFormat参数适配
String date1 = "2024-08-22 11:20:30.890";
//将时间的字符串转化为时间对象(java.util.Date)
Date ndate = sdf.parse(date1);
System.out.println(ndate);
}
传进去数据
public static void insert1(long id,
String name, int age, Date date) throws Exception {
SimpleDateFormat sdf =
new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
String ndate = sdf.format(date);
//1、注册驱动 XXXDriver
Class.forName("com.mysql.cj.jdbc.Driver");
//请求资源定位符,协议://ip:port/database
String url = "jdbc:mysql://192.168.174.136:3306/gather";
//2、获取连接
Connection conn =
DriverManager.getConnection(
url, "root", "root");
//3、创建Statement对象或者PreparedStatement对象
Statement sts = conn.createStatement();
//4、执行sql语句
boolean b = sts.execute("insert into student " +
"values(" + id + ",'" + name + "'," + age + ",'" + ndate + "')");
System.out.println(b);
//5、执行的sql有结果返回处理结果,没有结果执行第6步
//6、关闭资源,正开倒关
if (sts != null) sts.close();
if (conn != null) conn.close();
}
可以执行多条,每次调用一次execute执行一条语句
PreparedStatement直接传sql语句去执行,只执行了一条
PreparedStatement执行时不需要传数据,数据的位置全都用?去表示
public static void insert_test1() throws ClassNotFoundException, SQLException {
//1、注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2、获取连接
Connection conn =
DriverManager.getConnection(
"jdbc:mysql://192.168.174.136:3306/gather",
"root", "root");
String sql = "insert into student " +
"values(?,?,?,?)";
//3、创建PreparedStatement,sql中的?表示占位操作,
//先将sql发送给数据库,后每次只需要传数据就可以
PreparedStatement ps = conn.prepareStatement(sql);
//3、创建PreparedStatement,sql中的?表示占位操作,
//先将sql发送给数据库,后每次只需要传数据就可以
PreparedStatement ps = conn.prepareStatement(sql);
//第一个参数表示问号的位置,是第几个问号,第二个参数表示问号代表的数据
ps.setLong(1, 7);
ps.setString(2, "zhaoliu1");
ps.setInt(3, 28);
//如果数据库的字段是时间类型,java中对象的是java.sql.Date
Date date = new Date();//java.util.Date
ps.setDate(4,
new java.sql.Date(date.getTime()));
//4、执行sql语句,execute每执行一次,数据发送数据库执行一次sql
//boolean b=ps.execute();
//把当前构建的一行数据写入缓存,最后一次把n行数据一次性发给数据库
//批处理,需要评估
ps.addBatch();
mysql优化,尽量少用**,在数据库底层要多进行一个操作:用星号去匹配表中所有的列
//executeQuery返回一个结果集
ResultSet rs = sts.executeQuery(sql); //判断下一行是否有数据
一执行,当前事务默认提交,如果希望在所有sql语句执行都成功的时候再提交,那我们可以在获取连接之后
所有的sql执行完没有落地到数据库,需要再最后面做一个commit提交操作
数据库连接池
注册驱动时在当前jvm中去标识当前jdbc要连接哪个数据库
//1、注册驱动 XXXDriver Class.forName("com.mysql.cj.jdbc.Driver")
作用:加载驱动程序,把mysql驱动程序加载进来,再一个就是要让jvm知道你要连接哪一个数据库
//请求资源定位符,协议://ip:port/database String url = "jdbc:mysql://192.168.174.136:3306/gather";
目的:基于IP从网络中找到计算机,然后在这台计算机上找到3306端口服务,然后找到端口服务下的database,URL正确,然后才会去验证用户名和密码
在多并发的情况下,过程耗时,在connection连接对象获取时比较耗时
连接池:在企业当中,项目启动时会提前构建很多connection连接对象,这些连接对象直接放到放到一个集合里,用户要操作数据库时直接去集合里取,用完在放回
连接池在java中要考虑线程安全和线程不安全,在并发环境下使用,那么连接池可以使用Vector,如果不考虑并发情况,ArrayList(本身线程不安全)也可以
//2、获取连接
Connection conn =
DriverManager.getConnection(
url, "root", "root");
连接池原理
public class ConnectionPool {
private static List<Connection> pool=new ArrayList<>();//新建一个连接池对象
//获取连接对象的方法
public static void getConnection(){
nnConnection
}
}
如果现在连接池集合和方法都构建成静态的,此时放入连接对象的过程写到静态代码块里
如果他们不是静态的,可以把 List<Connection> pool=new ArrayList<>();写到构造器里。将来构建ConnectionPool对象的时候,连接池已经准备好了
但是连接池一般是共用的,所以多数情况写成静态的
public class ConnectionPool {
private static List<Connection> pool=new ArrayList<>();
static{
Class.forName("com.mysql.cj.jdbc.Driver");
for(int i=0;i<20;i++){
Connection conn=DriverManager.getConnection(
"jdbc:mysql://192.168.174.136:3306/gather",
"root","root");//构建连接对象
pool.add(conn);
}
public static void getConnection(){
nnConnection
}
}
将来ConnectionPool 这个类加载到jvm方法区的时候,静态代码块完成初始化操作,连接对象也构建好了
到此初始化完成
getConnection()
public static Connection getConnection(){
Connection conn=pool.remove(0);
return conn;//返回连接对象
}
取完之后连接对象能不能让多个人用一个?
为什么不用get去取,取完再删?
因为remove根据角标去移除元素时会返回移除掉的元素本身,既能完成元素的取值又能完成元素的删除动作
如果现在去取,取完之后没有了? 在取之前先做一个判断,不等于0时取出
public static Connection getConnection(){
Connection conn=null;
if(pool.size()!=0){
conn=pool.remove(0);
}
return conn;
}
等于0时怎么做?
1.再次创建,在else里再构建一个新的连接对象
2.在静态方法上加锁 这里代表的是this.getclass 即它的运行时类对象,如果没有static,则代表当前对象本身
public static Connection getConnection()
synchronized(ConnectionPool.class){//当前运行时类做锁对象
Connection conn=null;
if(pool.size()!=0){
conn=pool.remove(0);//从pool集合里去取,然后得到Connection连接对象
}else{
ConnectionPool.class.wait();
}
return conn;
}
}
用完啦放回来
public static void putConnection(Connection conn){
//加上锁对象,要和获取连接的锁对象是同一个
synchronized (ConnectionPool.class){
pool.add(conn);
if(pool.size()==1) {
//放完之后通知等待的
ConnectionPool.class.notifyAll();
}
}
}
ArrayList是线程不安全的,如何调整使得线程安全?
运用collections工具类
现在数据仿真模块完成了
然后把日志基于采集模块去读,读了之后把数据封装成List集合,List集合存放Environment对象,
读数据的话关键在于流的选择,RandomAccessFile,指定Env.log文件路径和模式
也可以用BufferedReader缺点是读到什么位置不好记录
String line = "";//当前行标记
while ((line = rand.readLine()) != null) {
}
//然后测试一下是否可以读到数据
while ((line = rand.readLine()) != null) {
System.out.println(line);
}
//接下来数据拆分
while ((line = rand.readLine()) != null) {
String[] lines = line.split("[|]");
if (lines.length != 9) continue;//判断拆分项数
拿数据的时候拿哪个作为标识?
先构建出Evironment对象,封装时需要很多Environment对象,所以需要构建一个集合来存储环境对象
先拿到的是16进制,需要先转成10进制才能计算
得到温度和湿度之后,接下来构建对象
//代码调优
//把通用的部分提出来
//定义一个私有方法
private Environment
createEnv(String[] lines,String name,double data){
Environment hum_en=new Environment();
hum_en.setName(name);
hum_en.setSrcID(lines[0]);
hum_en.setDstID(lines[1]);
hum_en.setDevID(lines[2]);
hum_en.setSensorAddress(lines[3]);
hum_en.setCounter(lines[4]);
hum_en.setCmd(lines[5]);
hum_en.setData(data);
hum_en.setStatus(lines[7]);
hum_en.setGather_date(Long.parseLong(lines[8]));
return hum_en;
}
else {
int data=Integer.parseInt(lines[6].substring(0,4),16);
Environment en=createEnv(lines,"光照强度",data+0.0);
logger.debug(count+"行采集光照强度数据:"+en);
list.add(en);
}
采集完毕,然后是跨时段的问题,如果每小时采集一次,那么第二个小时在采集时不能读到已经读过的数据 while之后
//获取本次文件读取的最后位置
long position=rand.getFilePointer();
//然后将其写到文件里去
savePosition(pointerPath,position);
自动生成方法
//往文件里写是long类型,基本类型的读写用DataInputStream或DataOutputStream
//保存日志读取的最后位置到文件中
private void savePosition(String path, long position) {
DataOutputStream dos= new DataOutputStream(new FileOutputStream(path));
dos.writeLong(position);
dos.flush();
if(dos!=null)dos.close();
}
rand.seek(before_position);
//跳过上次采集的最后位置
//读取上次日志读取的最后位置
private long loadPosition(String path) {
long pointer=0L;
return pointer;//即使将来没有,返回0
}
//假设现在运行,有没有文件?需要file对象判断
private long loadPosition(String path) {
long pointer=0L;
File file=new File(path);
if(file.exists()){
DataInputStream dis=
new DataInputStream(
new FileInputStream(file));
pointer=dis.readLong();
}
return pointer;
}
//文件存在就读(DataInputStream),文件不存在直接返回0
//现在采集端完成了
//客户端程序
项目的配置,我们要把整个个项目中可变的路径,参数提到配置文件,configuration对象本身有各个模块对象构建的方法,用configuration对象管理这些对象的同时,要保证客户端构建的时候所有对象只构建一个,然后服务器构建的时候所有对象只构建一个,所有需要的对象去configuration里去取