物联网环境监测数据中心‌Day04

gkbmnkgnbkgfnjnkjbnkjn关于数据库连接jdbc

mysql权限不足如何处理

  1. execute 执行任意sql,不能获取数据库的结果,返回boolean表示查询是否有结果

  2. executeUpdate 执行insert、delete、update,返回值int,表示当前sql影响 数据库表的行计数

  3. 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里去取

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值