引言
经过几天的面向百度和csdn,以及和无数java中的对象谈恋爱,终于弄清除了JDBC连接数据库的来龙去脉。因此本帅决定记录下本帅从搭建服务器到运行到Android摸索的全过程,也算给小白们些许福利!话不多说,让我们开始吧!
步骤
JDBC(Java DataBase Connection)的前提工作
a. JDBC如果没有服务器,首先需要搭建本地的局域网服务器
详情见传送门大娃
传送门大娃子:本地服务器的搭建
b. 搭建好服务器以后,需要创建可远程访问mysql数据库权限的用户
详情见传送门二娃
传送门二娃子:创建可远程访问mysql数据库权限的用户
c. 当完成好前面两步以后,需要下载MySQL Connector for Java(Mysql 提供给Java连接数据库的接口)驱动,并在Android studio 中配置好,具体配置见传送门三娃
连接JDBC
d. 当完成好上述JDBC连接的准备工作以后,就可以着手连接JDBC了
1.首先我们需要在mysql中创建数据库,和数据表。(如果数据表中没法插入中文,请参考传送门四娃。)
传送门四娃:phpMyAdmin中文无法插入的编码问题的解决
2.写JDBC加载驱动获得JDBC连接的代码
Class.forName(com.mysql.jdbc.Driver) 通过反射加载驱动类(按照类名加载)
Connection connection = DriverManager.getConnection(url,username,password);
3.获取连接中的三个参数url,username,password
String url = “jdbc:mysql://服务器ip地址:数据库的访问端口/数据库名称”
String username = 创建的可远程访问mysql权限的用户的用户名
String password = 创建的可远程访问mysql权限的用户的密码
其中 服务器ip地址的获得 来自 dos命令下输入ipconfig,
数据库的访问端口来自登入phpMyadmin下,上方显示的端口(一般为3306,如果你未更改过端口的话)
通过以上的步骤,小伙伴们就能够连上远程服务器的mysql数据库的具体某个数据库啦,具体步骤请参考传送门五娃
传送门五娃:连接远程mysql数据库中的具体某个数据库
e. 连接上mysql远程数据库中的具体数据库后,对该数据库的表的操作,需要掌握的知识:
statement(statement(sql注入),preparedstatement等)
Resultset(查询的结果集)等
由于发现JDBC的增删改查的代码存在同一耦合的代码,为4中所提到的加载驱动获取连接以及资源使用后的释放代码(connection,statement,resultset),所以单独提取除了一个工具类JDBCUtil,详情见传送门六娃:
传送门六娃: JDBC增删改查操作以及JDBCUtil封装工具类
f. 提取出JDBC工具类以及实现JDBC增删改查代码以后,我们需要设置两个测试,
一个是面向Android studio的控制台的测试类(有Main方法的类,输出在Android studio控制台上)
一个是面向Android 的测试Activity(理论上来讲,能在main中运行测试以后,基本也能在手机的Activity中运行)
先在有主方法的类中测试JDBC的增删改查操作是否没有问题,部分测试代码如下:(主要提供思路,小伙伴们最好自行写代码测试哟!)
package com.example.paoduantui.JDBC.testJDBC;
import android.os.SystemClock;
import com.example.paoduantui.JDBC.JDBCDAO.PositionDBDao;
import com.example.paoduantui.JDBC.JDBCDAO.TaskDBDao;
import com.example.paoduantui.JDBC.JDBCDAO.UserDBDao;
import com.example.paoduantui.JDBC.JDBCDB.PositionDB;
import com.example.paoduantui.JDBC.JDBCDB.TaskDB;
import com.example.paoduantui.JDBC.JDBCDB.UserDB;
import com.example.paoduantui.Task;
import java.util.List;
//测试JDBCDao类
/**
* 创建了四个线程,分别执行了增删改查操作
* 测试了dao类
* main方法中能调用的,Activity中也可以
* */
public class testJDBCDao {
public static void main(String[] args){
//插入线程
new Runnable() {
@Override
public void run() {
//TaskDB taskDB = new TaskDB(1,1,"张大帅比",'1',"张斌真帅","","2015-06-14","2015-06-14",'7');
PositionDB positionDB = new PositionDB(1,1,1,1,"","","");
int result= PositionDBDao.insert(positionDB);
if(result==1) System.out.print("插入数据成功!");
}
}.run();
//查询线程
new Runnable() {
@Override
public void run() {
List<TaskDB> list = TaskDBDao.getAll();
for(int i= 0;i<list.size();i++){
System.out.println(list.get(i).getId()+list.get(i).getUsername());
}
}
}.run();
//删除线程
new Runnable() {
@Override
public void run() {
TaskDB taskDB1=new TaskDB(9,1,"张斌斌",1,"张斌斌摔倒的","","","",7);
int result1 = TaskDBDao.deleteByTaskId(taskDB1);
if(result1==1)System.out.println("删除数据成功!!"+taskDB1.getTaskid());
}
}.run();
//更新线程
new Runnable() {
@Override
public void run() {
TaskDB taskDB1=new TaskDB(1,1,"张斌斌",1,"张斌斌摔倒的","","","",7);
int result1 = TaskDBDao.updateByTaskId(taskDB1);
System.out.println("更新数据成功!!"+taskDB1.getTaskid());
}
}.run();
}
}
将没有问题的方法再放入Android 的Activity中测试,此时,会发现在含有主方法的类中能运行的某些方法在Android设备上运行会闪退,
究其原因有以下几种可能:(通过检查一一排除)
1.连接远程mysql服务器,本质是TCP连接(访问,返回数据),因此需在AndroidManifest.xml文件中添加网络权限
2.需要添加连接JDBC的许可协议(本帅也不知道这是什么鬼,望大神告知)(在需要用到JDBC的Activity的oncreat加载布局后添加上以下代码:)//添加许可协议,不加的话,闪退 StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); StrictMode.setThreadPolicy(policy);
- 当第一次进入界面可以成功使用JDBC的操作,而第二次进去会闪退,主要是因为,Android不支持将JDBC放在主线程中,因此需要调用线程来完成JDBC的操作
当在含有主方法的类中以及Activity中均测试完以后,意味着Android端可以利用JDBC来成功访问远程mysql远程数据库啦!!(贴上我用来测试的Activity代码)
package com.example.paoduantui.JDBC.testJDBC;
import android.os.StrictMode;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import com.example.paoduantui.JDBC.JDBCDAO.TaskDBDao;
import com.example.paoduantui.JDBC.JDBCDAO.UserDBDao;
import com.example.paoduantui.JDBC.JDBCDB.TaskDB;
import com.example.paoduantui.JDBC.JDBCDB.UserDB;
import com.example.paoduantui.R;
import java.util.List;
//在main方法中或在activity中不能将JDBC操作数据库放在主线程里
public class testJDBCActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test_jdbc);
final TextView textView = findViewById(R.id.textView);
Button insert =findViewById(R.id.insert);
Button delete =findViewById(R.id.delete);
Button query = findViewById(R.id.query);
Button update = findViewById(R.id.update);
//添加许可协议,不加的话,闪退
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
//开启新线程,插入数据
final Runnable runnable1=new Runnable() {
@Override
public void run() {
TaskDB taskDB = new TaskDB(1,1,"张大帅比",'1',"张斌真帅","","2015-06-14","2015-06-14",'7');
int result=TaskDBDao.insert(taskDB);
if(result==1)Toast.makeText(testJDBCActivity.this,"插入数据成功!",Toast.LENGTH_LONG).show();
else Toast.makeText(testJDBCActivity.this,"不要在点击了,已经插入成功了!!",Toast.LENGTH_LONG).show();
}
};
//开启新线程,删除数据
final Runnable runnable2 = new Runnable() {
@Override
public void run() {
TaskDB taskDB = new TaskDB(1,1,null,0,null,null,null,null,0);
int result = TaskDBDao.deleteByTaskId(taskDB);
if(result==1) Toast.makeText(testJDBCActivity.this,"删除数据成功!",Toast.LENGTH_LONG).show();
}
};
//开启新线程,连接JDBC,防止主线程阻塞,查询
final Runnable runnable = new Runnable() {
@Override
public void run() {
String str="";
List<TaskDB> list = TaskDBDao.getById(1, 0);
for (int i = 0; i < list.size(); i++) {
str += list.get(i).getId() + list.get(i).getUsername();
}
//Toast.makeText(testJDBCActivity.this, str, Toast.LENGTH_LONG).show();
textView.setText(str);
}
};
//更新线程
final Runnable runnable3 = new Runnable() {
@Override
public void run() {
TaskDB taskDB = new TaskDB(2,1,"彬彬",0,"","","","",0);
int result = TaskDBDao.updateByTaskId(taskDB);
if(result==1) Toast.makeText(testJDBCActivity.this,"更新成功!!",Toast.LENGTH_LONG).show();
}
};
insert.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
runnable1.run();
}
});
delete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
runnable2.run();
}
});
query.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
runnable.run();
}
});
update.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
runnable3.run();
}
});
//Toast.makeText(this, str, Toast.LENGTH_SHORT).show();
}
}
g.根据数据库中所建的表建相应的实体类DB类(表中字段即为类中的成员变量)
package com.example.paoduantui.JDBC.JDBCDB;
//数据库user表的实体类
public class UserDB {
private int id;//id
private String username;//用户名
private String password;//密码
private int image;//头像
//insert into user(id,username,password,image) values (getId,getUsername,getPassword,getImage);
//表名可以通过解析对象userDB,规定user_DB为其对象,解析对象即可
//通过占位符,四个占位符,for(int i = 1;i<count;i++) ?,
//ps.setObject(1,getId) 通过反射获取
//ps.setObject(4,getImage)
private final int count = 4;//该表有四个字段
public UserDB() {
}
//构造函数以及其getter setter 方法
public UserDB(int id, String username, String password, int image) {
this.id = id;
this.username = username;
this.password = password;
this.image = image;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getImage() {
return image;
}
public void setImage(int image) {
this.image = image;
}
}
f.根据该表创建出相应的数据库操作类Dao类(本帅一般创建增删改查(其中查又细分为查所有getAll,按条件查等,getById,getCondition(如模糊查找)等)类)
package com.example.paoduantui.JDBC.JDBCDAO;
import android.widget.Switch;
import com.example.paoduantui.JDBC.JDBCDB.UserDB;
import com.example.paoduantui.JDBC.JDBCUtil;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
//user表的数据库操作类
/**
* 里面的方法全为静态方法,用 UserDBDao.方法名 直接调用
* insert方法(增),deleteById方法(删),updateById方法(改),(参数均为UserDB)
* getAll(返回为UserDB的链表集合)(无参数)以及getById(返回为UserDB的链表集合)(_id ,type)(查)
* */
public class UserDBDao {
private static Connection connection;//获取连接(跑断腿App的连接)
private static PreparedStatement ps;//准备好的sql陈述
private static ResultSet rs;//结果集
//增
/**
* 返回int类型的insert数据库操作
* 参数为UserDB
* */
public static int insert(UserDB userDB){
try {
connection = JDBCUtil.getConnection();
String sql = "insert into user(id,username,password,image) values (?,?,?,?)";
ps = connection.prepareStatement(sql);
ps.setObject(1,userDB.getId());
ps.setObject(2,userDB.getUsername());
ps.setObject(3,userDB.getPassword());
ps.setObject(4,userDB.getImage());
int result = ps.executeUpdate();
return result;
} catch (SQLException e) {
e.printStackTrace();
}finally {
JDBCUtil.close(null,ps,connection);
}
return 0;
}
//删
/**
* 返回int类型的deleteById数据库操作
* 参数为UserDB
* */
public static int deleteById(UserDB userDB){
try {
connection = JDBCUtil.getConnection();
String sql = "delete from user where id = ?";
ps = connection.prepareStatement(sql);
ps.setObject(1,userDB.getId());
int result = ps.executeUpdate();
return result;
} catch (SQLException e) {
e.printStackTrace();
}finally {
JDBCUtil.close(null,ps,connection);
}
return 0;
}
/**
* 返回int类型的updateById数据库操作
* 参数为UserDB
* */
public static int updateById(UserDB userDB){
try {
connection = JDBCUtil.getConnection();
String sql = "update user set username = ? , password = ? , image = ? where id = ?";
ps = connection.prepareStatement(sql);
//ps.setObject(1,userDB.getId());
ps.setObject(1,userDB.getUsername());
ps.setObject(2,userDB.getPassword());
ps.setObject(3,userDB.getImage());
ps.setObject(4,userDB.getId());
int result = ps.executeUpdate();
return result;
} catch (SQLException e) {
e.printStackTrace();
}finally {
JDBCUtil.close(null,ps,connection);
}
return 0;
}
/**
* 返回List<UserDB>类型的获取表中所有数据的数据库操作
* */
public static List<UserDB> getAll(){
List<UserDB> list = new ArrayList<>();
try {
connection = JDBCUtil.getConnection();
String sql = "select * from user order by id desc";//降序排列,使得每次第一条记录永远是最新的记录
ps = connection.prepareStatement(sql);
rs = ps.executeQuery();
while (rs.next()){
int id = rs.getInt(1);
String username = rs.getString(2);
String password = rs.getString(3);
int image = rs.getInt(4);
UserDB userDB = new UserDB(id,username,password,image);
list.add(userDB);
}
return list;
} catch (SQLException e) {
e.printStackTrace();
}finally {
JDBCUtil.close(rs,ps,connection);
}
return null;
}
/**
* 返回List<UserDB>类型的根据不同id的类型获取表中数据的数据库操作
* 其中参数_id 表示id的值,type表示id的类型 0:id(用户id),1:taskid(任务id),2:jdr_id(接单人id)
* */
public static List<UserDB> getById(int _id,int type){
String selection = null;
List<UserDB> list = new ArrayList<>();
switch (type){
case 0:
selection = "id";
break;
case 1:
selection="taskid";
break;
case 2:
selection="jdr_id";
break;
}
try {
connection = JDBCUtil.getConnection();
String sql = "select * from user where "+ selection + "= ? ";//通过拼接的sql来查询不同id下的数据
ps = connection.prepareStatement(sql);
ps.setObject(1,_id);
ResultSet rs = ps.executeQuery();
while (rs.next()){//注意,此处的结果集不同于sqlite的游标集,下标是从1开始的
int id = rs.getInt(1);
String username = rs.getString(2);
String password = rs.getString(3);
int image = rs.getInt(4);
UserDB userDB = new UserDB(id,username,password,image);
list.add(userDB);
}
return list;
} catch (SQLException e) {
e.printStackTrace();
}finally {
JDBCUtil.close(rs,ps,connection);
}
return null;
}
}
至此,JDBC到这儿就完美收官啦!期待与小伙伴们的再次相遇!