AndroidStudio通过JDBC连接MySQL数据库六大巨坑

注意

很多朋友用IDEA通过JDBC的方式去连接MYSQL数据库JDBC之获取数据库连接方法详解,然后看到这里用Androidstudio通过JDBC的方式去连接MYSQL数据库是不是也是像我前两天一样,不以为然呢?是不是以为贴过java代码就行了呢?还请听我细细道来

基础

需要会使用IDEA编译器用java代码通过JDBC的方式,来连接MySQL数据库,最好还是先看完这篇博客:JDBC之获取数据库连接方法详解,然后再看Androidstudio 这篇

Androidstudio通过JDBC连接数据库巨坑介绍(这里呢,我使用我所做项目的修改密码界面来做介绍)

1.网络权限问题(打不开apk)

Android Studio默认是不允许访问Internet的。因此需要在app/src/main/AndroidManifest.xml中的<manifest>...</manifest>区域内添加一行在 ,AndroidManifest.xml 中(别去加在<application></application>里面)添加:

<uses-permission android:name="android.permission.INTERNET" />

2.jar包问题(找不到driver)

这里的
我的jar包用的是5.0.8版本的,jar包的话,去官网下载,建议版本不要太高,版本太高问题超级多

3.连接方法问题(返回连接对象为null)

 Connection conn=DriverManager.getConnection(url,user,password);
 Driver driver=new com.mysql.jdbc.Driver();
        Properties info =new Properties();
        info.setProperty("user","root0");
        info.setProperty("password","abc123");
Connection conn=driver.connect(url,info);

连接之前记得加载一下驱动类就行,刚开始我的Connection返回对象一直为null,我一直以为是连接方式有问题,我试完这两种连接方式,于是Connection返回对象一直为null,至于为什么返回null的话,请看下一个巨坑。

4.异步启动问题(返回连接对象为null)

同步启动

刚开始我直接把连接过程写在主线程里面,所以造成了上面那种尴尬的情况,Connection返回对象一直是null,查了一下原因如下:
一个APP如果在主线程中请求网络操作,将会抛出NetworkOnMainThreadException异常。Android这个设计是为了防止网络请求时间过长而导致界面假死的情况发生,我试了直接不是假死,而是直接返回null值,然后就gg了。

  static void connect(){
    
    
  //1.读取配置文件中的四个基本信息
            String url = "jdbc:mysql://"+ip+"/"+数据库名;
            String user_server = 用户名;
            String password_server = 密码;
            String driverclass = "com.mysql.jdbc.Driver";
            //2.加载驱动
            try {
    
    
                Class.forName(driverclass);
            } catch (ClassNotFoundException e) {
    
    
                e.printStackTrace();
            }
             conn = null;
            //3.获取连接
            try {
    
    
                conn = DriverManager.getConnection(url, user_server, password_server);
            } catch (SQLException throwables) {
    
    
                throwables.printStackTrace();
            }


            //4.预编译sql语句,返回PreparedStatement的实例
             sql="select * from login ";
            try {
    
    
                ps=conn.prepareStatement(sql);
                //6.执行并返回结果集
                ResultSet resultSet =ps.executeQuery();
                while(resultSet.next()){
    
    
                    String usertest=resultSet.getString(1);
                    String passwordtest=resultSet.getString(2);
                    if(usertest.equals(user)){
    
    

                        if(password_before.equals(passwordtest)) {
    
    
                            String sql2 = "update login set password=? where user=?";
                            ps = conn.prepareStatement(sql2);
                            //5.填充占位符
                            ps.setString(1, password_after);
                            ps.setString(2, user);
                            //6.执行操作
                            ps.execute();
                            flag_test=1;
                            return;
                        }
                        flag_test=2;
                        return;
                    }
                }
                flag_test=0;
            } catch (SQLException e) {
    
    
                e.printStackTrace();
            }

            flag_test=0;
                return ;
             }

当你执行到下面这行的时候,然后就会返回null值,紧接着下面也就没有任何意义

conn = DriverManager.getConnection(url, user_server, password_server);

可以断点调试看看

异步启动

Android在子线程中是不可以进行ui操作的。Toast也是不可以在子线程中使用的。


 Thread threads=new Thread(new Runnable() {
    
    
        public void run() {
    
    

            //1.读取配置文件中的四个基本信息
            String url = "jdbc:mysql://"+ip+"/"+数据库名;
            String user_server = 用户名;
            String password_server = 密码;
            String driverclass = "com.mysql.jdbc.Driver";
            //2.加载驱动
            try {
    
    
                Class.forName(driverclass);
            } catch (ClassNotFoundException e) {
    
    
                e.printStackTrace();
            }
             conn = null;
            //3.获取连接
            try {
    
    
                conn = DriverManager.getConnection(url, user_server, password_server);
            } catch (SQLException throwables) {
    
    
                throwables.printStackTrace();
            }


            //4.预编译sql语句,返回PreparedStatement的实例
             sql="select * from login ";
            try {
    
    
                ps=conn.prepareStatement(sql);
                //6.执行并返回结果集
                ResultSet resultSet =ps.executeQuery();
                while(resultSet.next()){
    
    
                    String usertest=resultSet.getString(1);
                    String passwordtest=resultSet.getString(2);
                    if(usertest.equals(user)){
    
    

                        if(password_before.equals(passwordtest)) {
    
    
                            String sql2 = "update login set password=? where user=?";
                            ps = conn.prepareStatement(sql2);
                            //5.填充占位符
                            ps.setString(1, password_after);
                            ps.setString(2, user);
                            //6.执行操作
                            ps.execute();
                            flag_test=1;
                            return;
                        }
                        flag_test=2;
                        return;
                    }
                }
                flag_test=0;
            } catch (SQLException e) {
    
    
                e.printStackTrace();
            }

            flag_test=0;
                return ;
        }
    });
threads.start();

这样的话,就能启动成功喽,但是注意一点,这种方式,只能运行一次,如果点击了两次的话,那么也就相当于,这个线程对象调用了两次start函数,这能行吗?????。但是我们进行修改密码然后点击按钮判断的时候,就只是点击一次,然后手动返回上个页面了吗?,答案肯定不是的。

5.同一个线程不能多次调用异步启动函数(threads.start()------>new Thread(threads).start();)(java.lang.IllegalThreadStateException报错,闪退问题)

这里也就是解决4的问题,threads.start();,你点击几次按钮,那么它就会调用几次start函数,你能把一个thread对象连续start吗?肯定不能!所以等你点击第二次的时候,那么就报错了,IllegalThreadStateException紧接着闪退了,
在这里插入图片描述
这算是一次点击,对吧?也就是相当于调用了一次threads.start();,如果我们继续在这页面输入内容加密码这些东西,再次进行判断,是不是相当于第二次调用threads.start(),然后就闪退,变成如下界面,也就是上一个activity了,并且IllegalThreadStateException报错
在这里插入图片描述
那么我们该如何解决呢?出发点肯定是不能让一个线程调用两次start函数,对吧?那么每次都new一个thread不就得了嘛,对吧,或者搞一个thread数组,换着使用

  new Thread(threads).start();

6.线程函数中弹出Toast问题

如果在连接上的时候需要一个toast提示一下,连接成功(修改密码前提肯定是连接数据库嘛)或者修改密码成功的话,那么是不是会在线程函数中写上:

 Toast.makeText(getApplicationContext(), "修改密码成功", Toast.LENGTH_SHORT).show();

线程函数中能不能直接toast呢?(答案肯定是不能呀 ,如果在线程函数中,直接写的话,毫无疑问报错java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()Android在子线程中是不可以进行ui操作的。Toast也是不可以在子线程中使用的。
在调用Toast之前,需要先创建一个Looper对象,这样做,我们所调用的Toast才能加入到一个消息队列中,并向屏幕进行输出显示。而我们之所以在MainActivity类中可以直接调用Toast而无需在其前面创建一个Looper对象,是因为当我们进行程序编译时,Android框架会默认为我们创建出一个Looper对象。
所以在线程函数中调用 Toast的话,需要如下操作:

Looper.prepare();
Toast.makeText(getApplicationContext(), "修改密码成功", Toast.LENGTH_SHORT).show();
Looper.loop();

那么我们可不可以设置一个全局变量flag,然后在线程函数里面设置flag的值,然后出来之后,利用一个judge_after函数来进行toast操作呢?在线程函数里面保证只进行连接和设置flag 的作用,其它的在主线程里面进行会比较方便,因为异步线程,没法进行断点调试,那样做起来调试时候比较让人难以接受,

7.修改密码框架模式问题(judge_before + judge +judge_after)

 Thread threads=new Thread(new Runnable() {
    
    
        public void run() {
    
    

            //1.读取配置文件中的四个基本信息
            String url = "jdbc:mysql://"+ip+"/"+数据库名;
            String user_server = 用户名;
            String password_server = 密码;
            String driverclass = "com.mysql.jdbc.Driver";
            //2.加载驱动
            try {
    
    
                Class.forName(driverclass);
            } catch (ClassNotFoundException e) {
    
    
                e.printStackTrace();
            }
             conn = null;
            //3.获取连接
            try {
    
    
                conn = DriverManager.getConnection(url, user_server, password_server);
            } catch (SQLException throwables) {
    
    
                throwables.printStackTrace();
            }


            //4.预编译sql语句,返回PreparedStatement的实例
             sql="select * from login ";
            try {
    
    
                ps=conn.prepareStatement(sql);
                //6.执行并返回结果集
                ResultSet resultSet =ps.executeQuery();
                while(resultSet.next()){
    
    
                    String usertest=resultSet.getString(1);
                    String passwordtest=resultSet.getString(2);
                    if(usertest.equals(user)){
    
    

                        if(password_before.equals(passwordtest)) {
    
    
                            String sql2 = "update login set password=? where user=?";
                            ps = conn.prepareStatement(sql2);
                            //5.填充占位符
                            ps.setString(1, password_after);
                            ps.setString(2, user);
                            //6.执行操作
                            ps.execute();
                            flag_test=1;
                            return;
                        }
                        flag_test=2;
                        return;
                    }
                }
                flag_test=0;
            } catch (SQLException e) {
    
    
                e.printStackTrace();
            }

            flag_test=0;
                return ;
        }
    });

     public boolean thread_before(){
    
    
         EditText user_text = findViewById(R.id.username);
         user = user_text.getText().toString();

         EditText password_text = findViewById(R.id.password_before);
         password_before = password_text.getText().toString();

         EditText password_text_ = findViewById(R.id.password_after);
         password_after = password_text_.getText().toString();

         if(user.equals("")&&password_before.equals("")&&password_after.equals("")){
    
    
             Toast.makeText(getApplicationContext(), "请输入用户名,原密码和修改密码", Toast.LENGTH_SHORT).show();
             return false;
         }else if(user.equals("")&&password_before.equals("")&&(!password_after.equals(""))){
    
    
             Toast.makeText(getApplicationContext(), "请输入用户名和原密码", Toast.LENGTH_SHORT).show();
             return false;
         }else if(user.equals("")&&(!password_before.equals(""))&&password_after.equals("")){
    
    
             Toast.makeText(getApplicationContext(), "请输入用户名和修改密码", Toast.LENGTH_SHORT).show();
             return false;
         }else if((!user.equals(""))&&password_before.equals("")&&password_after.equals("")){
    
    
             Toast.makeText(getApplicationContext(), "请输入原密码和修改密码", Toast.LENGTH_SHORT).show();
             return false;
         }else if(user.equals("")&&(!password_before.equals(""))&&(!password_after.equals(""))){
    
    
             Toast.makeText(getApplicationContext(), "请输入用户名", Toast.LENGTH_SHORT).show();
             return false;
         }else if((!user.equals(""))&&password_before.equals("")&&(!password_after.equals(""))){
    
    
             Toast.makeText(getApplicationContext(), "请输入原密码", Toast.LENGTH_SHORT).show();
             return false;
         }else if((!user.equals(""))&&(!password_before.equals(""))&&password_after.equals("")){
    
    
             Toast.makeText(getApplicationContext(), "请输入修改密码", Toast.LENGTH_SHORT).show();
             return false;
         }else if((!user.equals(""))&&(!password_before.equals(""))&&(!password_after.equals(""))&&password_before.equals(password_after)){
    
    
             Toast.makeText(getApplicationContext(), "原密码不能和修改密码相等", Toast.LENGTH_SHORT).show();
             return  false;
         }else if((!user.equals(""))&&(!password_before.equals(""))&&(!password_after.equals(""))&&(password_after.length()<6))
         {
    
    
             Toast.makeText(getApplicationContext(), "修改后密码长度不能小于6位", Toast.LENGTH_SHORT).show();
             return  false;
         }
         return true;
     }


    public void thread_after(){
    
    

        if(flag_test==1){
    
    
           Toast.makeText(getApplicationContext(), "修改密码成功", Toast.LENGTH_SHORT).show();
        }else if(flag_test==0){
    
    
           Toast.makeText(getApplicationContext(), "用户名错误", Toast.LENGTH_SHORT).show();
        }else if(flag_test==2){
    
    
            Toast.makeText(getApplicationContext(), "原密码错误", Toast.LENGTH_SHORT).show();
        }


    }


}

总结

这次Android的jdbc之旅呢,收获了很多,本以为和IDEA一样的操作,小改一下就行,结果踩中了那么坑,下次注意喽

猜你喜欢

转载自blog.csdn.net/CSNN2019/article/details/115098796