目录
报错
报错:java.sql.SQLException: Parameter index out of range (3 > number of parameters, which is 2).
错误详情:
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1074)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:988)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:974)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:919)
at com.mysql.jdbc.PreparedStatement.checkBounds(PreparedStatement.java:3813)
at com.mysql.jdbc.PreparedStatement.setInternal(PreparedStatement.java:3795)
at com.mysql.jdbc.PreparedStatement.setInternal(PreparedStatement.java:3840)
at com.mysql.jdbc.PreparedStatement.setInt(PreparedStatement.java:3784)
at cn.itcase.empdao.EmpDaoImpl.saveEmp(EmpDaoImpl.java:34)
at cn.itcase.empdao.EmpDaoImptest.testSave(EmpDaoImptest.java:26)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
需求分析与数据库编码
代码
数据库部分
需求:插入两条数据
李杰 18
张股 19
数据库需求分析
编号 员工姓名 年龄 部门
01 李俊杰 18 开发部
02 张三 19 开发部
部门字段存在数据冗余,为减少数据冗余 使用外键约束
整理上述得
编号 员工姓名 年龄 部门
01 李俊杰 18 1
02 张三 19 1
部门编号 部门名称
1 开发部
部门与员工之间的关系
一对多 一个部门有许多员工
设计数据库 需要遵循三大范式
第一范式:表的每个字段是不可分割的独立单元
第二范式:在第一范式的基础上,每个表只表达一个意思;理解:表的每个字段都和表的主键有依赖/有关系
第三范式:在第二范式基础,要求每张表的非主键字段都只能和主键有直接决定依赖关系 目的:降低数据冗余
员工表 从表 员工表中的一个字段引用了部门表的主键
部门表 主表
主表约束从表 主键约束外键 外键在从表中
从表被主表约束 外键被主键约束 主键在主表中(注意:每章表都由自己的主键)
数据库编码总体实现思路
建表
先建主表 在建从表
数据操作
添加数据: 先添加主表,再添加副表
修改数据: 先修改副表,再修改主表
删除数据: 先删除副表,再删除主表
开发步骤:
1.设计javabean 实体类 私有化属性private 有无参构造 提供公开的setter和getter方法
2.设计dao接口
3.dao实现类
4.测试
CREATE DATABASE demo18 DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; /*建库*/
USE demo18 /*使用数据库*/
CREATE TABLE dept( /*主表 部门表*/
deptId INT PRIMARY KEY AUTO_INCREMENT, /*部门id 主键约束(非空+唯一)自增长*/
deptName VARCHAR(20) NOT NULL /*部门名称 非空约束*/
)
CREATE TABLE employee( /*员工表 从表*/
empId INT PRIMARY KEY AUTO_INCREMENT ,/*员工id*/
empName VARCHAR(20) NOT NULL , /*员工姓名*/
age INT NOT NULL, /*年龄*/
dept_id INT NOT NULL , /*部门id 外键*/
CONSTRAINT employee_dept_Fk FOREIGN KEY(dept_id) REFERENCES dept(deptId) ON UPDATE CASCADE ON DELETE CASCADE
/* 外键约束 约束名称 外键 参考表(主键) 级联修改 级联删除 */
)
javaBean
代码实现
1.JavaBean
package cn.itcase.empdao;
public class Dept { // 部门实现体类
private int id;
private String deptName;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
public Dept(int id, String deptName) {
super();
this.id = id;
this.deptName = deptName;
}
public Dept() {
}
@Override
public String toString() {
return "Dept [id=" + id + ", deptName=" + deptName + "]";
}
}
package cn.itcase.empdao;
public class Eemployee {
private int empId;
private String empName;
private int age;
private Dept deptid;// 对应员工表的外键
public Dept getDept() {
return deptid;
}
public void setDept(Dept dept) {
this.deptid = deptid;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getEmpId() {
return empId;
}
public void setEmpId(int empId) {
this.empId = empId;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
public Eemployee(int empId, String empName, int age, Dept deptid) {
super();
this.empId = empId;
this.empName = empName;
this.age = age;
this.deptid = deptid;
}
public Eemployee() {
}
@Override
public String toString() {
return "Eemployee [empId=" + empId + ", empName=" + empName + ",age="
+ age + ",deptid=" + deptid + "]";
}
}
dao接口
2.dao
package cn.itcase.empdao;
public interface DeptEmpDao {
/**
* protected void save(Eemployee emp);
* 报错:
* 接口方法保存的非法修饰符;只允许公开和摘要
* @param emp
*/
public void saveEmp(Eemployee emp);
public void saveDept(Dept dept);
/*访问修饰符:
* private 私有控制访问符 被修饰的成员变量仅能被自身访问
* public 公共访问控制符 所有类都可以访问,但会降低运行安全性和数据的封装性,谨慎使用
* protected 保护访问控制符 主要是供子类引用,同一包中的其他类也可引用
* default 缺省默认访问符 没有定义成员变量的修饰符默认为default,可以被本类或同一包中的其他类访问
* 非访问修饰符
* static 静态域修饰符 用static修饰的成员变量仅属于本类的变量,而不属于任何一个具体对象,
* static修饰的成员变量保存在类的公共存储单元,该类任何对象访问它是获取的数据都市相同的
* 该类的任何对象修改它是,都是对同一内存单元进行操作
* final 最终域修饰符 修饰常量 被它修饰的常量在运行过程中常量的值不可再该变
* volatile 共享(易失)域修饰符 被它修饰的成员变量可能被几个线程控制和修改,一般用来修饰可接受外部输入的域
* transient 暂时性域修饰符 修饰暂时性变量
* */
}
daoImpl
3.dao实现类
package cn.itcase.empdao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import cn.itcase.util.JDBCUtil;
public class EmpDaoImpl implements DeptEmpDao {
// 全局变量
private Connection conn;
private PreparedStatement pstmt;
private ResultSet rs;
// 部门Id
int deptid=0;
@Override
public void saveEmp(Eemployee emp) {
// 保存员工
String sql_emp = "insert into employee(empName,dept_id)values(?,?,?)";
try {
// 连接数据库
conn = JDBCUtil.getConnection();
// 保存员工
pstmt = conn.prepareStatement(sql_emp);
pstmt = conn.prepareStatement(sql_emp,
Statement.RETURN_GENERATED_KEYS);
//员工id
//int EmpId =0;
// 设置参数
//pstmt.setInt(1,emp.getEmpId());
pstmt.setString(2, emp.getEmpName());
pstmt.setInt(3, emp.getAge());
pstmt.setInt(4, deptid); // 外键
// 执行预编译操作
pstmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCUtil.closeAll(conn, pstmt, rs);
}
}
@Override
public void saveDept(Dept dept) {
// 保存部门
String sql_dept = "insert into dept(deptName) values(?)";
// 部门id
deptid = 0;
try {
// 连接数据库
conn = JDBCUtil.getConnection();
/* 保存部门,获取自动增长 一.需要指定返回自动增长标记 */
pstmt = conn.prepareStatement(sql_dept,
Statement.RETURN_GENERATED_KEYS);
// 设置参数
//pstmt.setInt(1,dept.getId()); // 主键
pstmt.setString(2, dept.getDeptName());
// 执行
pstmt.executeUpdate();
/* 二.获取上面保存的部门自增长的主键 */
rs = pstmt.getGeneratedKeys();
// 得到返回自增长的字段
if (rs.next()) {
deptid = rs.getInt(1);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCUtil.closeAll(conn, pstmt, rs);
}
}
}
测试类
4.测试类
package cn.itcase.empdao;
import org.junit.Before;
import org.junit.Test;
public class EmpDaoImptest {
DeptEmpDao empDao = null;
@Before
public void init() {
empDao = new EmpDaoImpl();
}
@Test
public void testSave() {
try {
Dept dept = new Dept();
dept.setDeptName("");
empDao.saveDept(dept);
Eemployee emp = new Eemployee();
emp.setEmpName("");
emp.setAge(18);
emp.setDept(dept);
empDao.saveEmp(emp);
} catch (Exception e) {
e.printStackTrace();
}
}
}
工具类
JDBCUtil 工具类
package cn.itcase.util;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
/**
* JDBCUtil工具类
*
* @author Administrator
*
*/
public class JDBCUtil {
// static 修饰的成员属性 是共享数据 类加载时加载 类文件消失时消失
private static String url = "jdbc:mysql://localhost:3306/demo18"; // 连接数据库
// 等价上句代码 private staitc String url ="jdbc:mysql:///demo17";
private static String user = "root"; // 数据库的登录用户名
private static String password = "root"; // 数据库的登录密码
/**
* 获取连接的方法封装
*/
public static Connection getConnection() {
try {
// 加载驱动
Class.forName("com.mysql.jdbc.Driver");
return DriverManager.getConnection(url, user, password);
} catch (Exception e) {
throw new RuntimeException();
}
}
/**
* 释放资源的方法封装
*
* Connection 建立连接的对象 Statement 执行命令,将sql语句发送到数据库执行 ResultSet 保存查询结果对象
*/
public static void closeAll(Connection conn, Statement stmt, ResultSet rs) {
try {
if (rs != null) {
rs.close();
rs = null;
}
if (stmt != null) {
stmt.close();
stmt = null;
}
if (conn != null && conn.isClosed()) {
conn.close();
conn = null;
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}