框架就是软件的半成品,已经实现了很多功能,但是这些功能可以解决大部份软件的共性问题,现有的框架和你的产品业务无关,但是可以快速的帮你完成软件框架搭建,功能实现,部署。
高楼搭建:
打好地基,做框架(梁 板 柱),在每个楼层做隔断(小房间),进入装修
好处:速度快,结构稳定 , 非常灵活,定制化开发
高性能软件
使用框架 完成基础功能搭建(梁 板 柱),我们在根据不同业务在框架之上进行定制化开发
好处:开发速度快,周期短,稳定(一个非常初级的工程师都可以使用框架开发出非常稳定,可靠的应用),给了开发者很大的灵活性
后续学的都是框架:mybatis,spring,srpingmvc,springboot,springcloud,dubbo,mycat 目的: 高并发,高可靠
ORM:ORM(Object Relational Mapping)对象关系映射,简单理解,数据表中的一条数据可以映射为软件中的一个对象
ORM框架:解决的问题就是如何将数据表中的数据,读取出来,直接转换为对象,将java中的对象直接保存到数据库中,有时候也成为持久层框架,数据落地到数据库,掉电不丢失
包含:对象 增删改查 到数据库中
Java中常用orm:
mybatis: 常用,短小精悍,定制化sql语句
hibernate: 功能强大,不需要写sql语句,但是性能相对较差,不能根据需求优化sql, 逐步被淘汰
jdbcTemplate:底层封装了hibernate
使用JDBC完成ORM操作的缺点
存在大量的冗余代码。
手工创建 Connection、Statement 等。
手工将结果集封装成实体对象。
查询效率低,没有对数据访问进行过优化(Not Cache)。
MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。
iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。iBATIS提供的持久层框架包括SQL Maps和Data Access Objects(DAOs)
概述:
MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Ordinary Java Object,普通的 Java对象)映射成数据库中的记录。
官网:
https://mybatis.org/mybatis-3/zh/index.html
<dependencies>
<!--
mybatis jar 依赖
-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
<!--
mysql驱动
-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<!--
日志相关依赖 :记录日志 到文件 控制台中
-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
<!-- 单元测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
</dependency>
</dependencies>
/**
* 学生 与 student_tb 对应
*/
public class Student implements Serializable {
private int id;
private String name;
private int age;
private String sex;
private float height;
public Student() {
}
public Student(int id, String name, int age, String sex, float height) {
this.id = id;
this.name = name;
this.age = age;
this.sex = sex;
this.height = height;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public float getHeight() {
return height;
}
public void setHeight(float height) {
this.height = height;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
", height=" + height +
'}';
}
}
/**
* 学相关增删改查
* 现在 不要自己 实现这个接口 StudentDao
* 我们只要告诉mybatis 要实现这个接口
* 还要告诉实现的接口中的方法执行 哪个sql
*
*/
public interface StudentDao {
/**
* 查找所有学生
* select * from student_tb;
* @return
*/
List<Student> findAllStudent();
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--
mapper 就是 映射 sql 和 接口的映射
表中列名 和实体类 属性的映射
namespace 命名空间 和mybatis 二级缓存相关
-->
<mapper namespace="com.qfedu.dao.StudentDao">
<!--
select 代表执行 查询sql
id="findAllStudent" 对应namespace="com.qfedu.dao.StudentDao" 的那个方法
resultType="com.qfedu.entity.Student" 返回值类型 类 Student 并且存放到List 中
将每一行结果转化为 student 放到list
-->
<select id="findAllStudent" resultType="com.qfedu.entity.Student">
select id,name,age,sex,height from student_tb
</select>
</mapper>
在resources 下创建 mybatisConfig.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--
mybatis主配置
-->
<configuration >
<!--配置mybatis环境
default="mysql" 选择哪一个环境
-->
<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC"></transactionManager>
<!--配置数据源
POOLED 连接池形式
-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/java2102"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!--
<mappers> 配置
-->
<mappers>
<!--
告诉mybatis 要根据配置文件StudentDao.xml 的配置 生成 对应的接口实现类
-->
<mapper resource="com/qfedu/dao/StudentDao.xml"></mapper>
</mappers>
</configuration>
在resouces目录下创建log4j.properties
public class TestMyBatis01 {
private SqlSession sqlSession;
@Before // 初始化 sqlSes sion
public void init() throws IOException {
// 读取mybatis "mybatisConfig.xml"
InputStream inputStream = Resources.getResourceAsStream("mybatisConfig.xml");
// 工厂辅助类,帮助初始化 工厂 SqlSessionFactoryBuilder 建造者模式
SqlSessionFactoryBuilder sessionFactoryBuilder = new SqlSessionFactoryBuilder();
//SqlSessionFactory SqlSession 工厂,工厂设计模式
SqlSessionFactory sqlSessionFactory = sessionFactoryBuilder.build(inputStream);
// 创建sql 连接 相当于 jdbc connection
sqlSession = sqlSessionFactory.openSession();
}
@Test
public void finsAllStudentTest(){
//第一种: 调用方法全限定名 不回用
// List studentList = sqlSession.selectList("com.qfedu.dao.StudentDao.findAllStudent");
// 第二种
// 获取mapper 就是获取 接口StudentDao.class 对应的实现 对象
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
List<Student> studentList = studentDao.findAllStudent();
for (Student student:studentList){
System.out.println("student:"+student);
}
}
@After // 释放连接
public void destroy(){
sqlSession.close();
}
}
/**
* 根据 id 查找学生
* @param id
* @return
*/
Student findStudentById(int id);
<!--
select id,name,age,sex,height from student_tb where id = #{
id}
#{
id} 获取对应方法中的 参数 占位符
parameterType="integer" 请求参数类型 int integer
parameterType="java.lang.Integer"
parameterType 可以省略不写
尽量不要再 <select 中 写注释 否则容器干扰日志
-->
<select id="findStudentById" resultType="com.qfedu.entity.Student" >
/* 是的发送到发送到*/
<!--sdfsdfsdfds -->
select id,name,age,sex,height from student_tb where id = #{
id}
</select>
测试:
@Test// 根据iD 查询学生
public void findStudentByIdTest(){
Student student = studentDao.findStudentById(1);
System.out.println("student:"+student);
}
/**
* 增加学生
* 返回值 int 代表的是受影响的行数
* @param student
* @return
*/
int addStudent(Student student);
<!--
#{
name} 获取参数student对象中的属性值 addStudent(Student student);
-->
<insert id="addStudent" >
insert into student_tb (name,age,sex,height) values (#{
name},#{
age},#{
sex},#{
height})
</insert>
测试:
/**
* 增加学生
* 一开启自动提交
* sqlSessionFactory.openSession(true);
*/
@Test
public void addStudentTest(){
Student student = new Student();
student.setName("gaoyuan");
student.setAge(20);
student.setSex("M");
student.setHeight(175);
int num = studentDao.addStudent(student);
if (num>0){
System.out.println("增加成功");
}
}
/**
* 更新学生
* @param student
* @return
*/
int updateStudent(Student student);
<!--
更新学生
where id = #{
id} 必须要写
-->
<update id="updateStudent">
update student_tb set name = #{
name},age=#{
age},sex=#{
sex},height=#{
height} where id = #{
id}
</update>
测试:
/**
* 更新 学生 根据id
*/
@Test
public void updateStudentTest(){
Student student = new Student();
student.setName("gaoyuan");
student.setAge(24);
student.setSex("M");
student.setHeight(175);
student.setId(4);
int num = studentDao.updateStudent(student);
if (num>0){
System.out.println("更新成功");
}
}
/**
* 根据 id 删除 学生
* @param id
* @return
*/
int deleteStudentById(int id);
<!--
根据id 删除学生
-->
<delete id="deleteStudentById">
delete from student_tb where id = #{
id}
</delete>
/**
* 根据id 删除学生
*/
@Test
public void deleteStudentByIdTest(){
int num = studentDao.deleteStudentById(1);
if (num>0){
System.out.println("删除成功");
}
}
注意:
在增删改时,必须使用
1.自动提交 或者 手动commit
sqlSession = sqlSessionFactory.openSession(true);
2.更新 删除 必须加限定条件 where
自增id:当增加一条数据时,如果主键自增,则增的一行数据 id + 1
获取自增id :获取添加数据后的 增加的id
接口:
/**
* 获取 自增id(必须有自增主键)
*
*
* @param student
* @return
*/
int addStudentReturnId(Student student);
对应mapper :
<!--
获取取自增id 第一种方式
select last_insert_id() 获取最后插入的id
keyColumn="" 生成自增id 的 列
keyProperty="id" 在插入数据时parameterType="com.qfedu.entity.Student" 中的 属性id
resultType="int" 自增id 返回值类型
order="AFTER" 在插入之后执行
<selectKey 整个标签意义就算是在执行 insert 之后 执行 select last_insert_id()
并将查询 到的id 设置到 对象参数student addStudentReturnId(Student student))
-->
<!-- <insert id="addStudentReturnId" parameterType="com.qfedu.entity.Student">
insert into student_tb (name,age,sex,height) values (#{
name},#{
age},#{
sex},#{
height})
<selectKey keyColumn="id" keyProperty="id" resultType="int" order="AFTER">
select last_insert_id()
</selectKey>
</insert>-->
<!--
第二种方式获取自增id
useGeneratedKeys="true" 获取自增id
keyColumn="id" 读取那一列
keyProperty="id" 设置到参数 Student 对象 那个属性 id
-->
<insert id="addStudentReturnId" parameterType="com.qfedu.entity.Student" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
insert into student_tb (name,age,sex,height) values (#{
name},#{
age},#{
sex},#{
height})
</insert>
测试:
/**
* 获取自增id
*/
@Test
public void addStudentReturnIdTest(){
Student student = new Student();
student.setName("小明");
student.setAge(20);
student.setSex("M");
student.setHeight(175);
int num = studentDao.addStudentReturnId(student);
if (num>0){
System.out.println("增加成功");
System.out.println("自增id:"+student.getId());
}
}
like 模糊查询
/**
* 根据名称模糊 查询
* @param name
* @return
*/
List<Student> findStudentByLikeName(String name);
<!--
模糊查询 第一种方式#{
name}
resultType="com.qfedu.entity.Student" 将查询结果的每一行转化为 对应类型对象
#{
name} 获取参数 findStudentByLikeName(String name) name
#{
name} 是占位符 仅仅是替换 ? 输入的只能是值
select id,name,age,sex,height from student_tb where name like ?
-->
<!--<select id="findStudentByLikeName" resultType="com.qfedu.entity.Student">
select id,name,age,sex,height from student_tb where name like #{
name}
</select>-->
<!--
模糊查询 第二种方式 ${
value}
${
value} 就是获取 findStudentByLikeName(String name); name,只能是value
'%${value}%' ${
value} 他作用 是 将 参数进行 简单的替换 组装为新的 sql
如果传递的参数 是一个 sql 子语句,他会先执行 子语句,此时会发生 sql注入,造成数据安全
select id,name,age,sex,height from student_tb where name like '%小%' 仅仅是替换
-->
<select id="findStudentByLikeName" resultType="com.qfedu.entity.Student">
select id,name,age,sex,height from student_tb where name like '%${value}%'
</select>
测试:
/**
* 模糊查询
*/
@Test
public void findStudentByLikeNameTest(){
// #{name} %小% 只要含有 小 的行都查询出来
// List studentList = studentDao.findStudentByLikeName("%小%");
// 第二种模糊查询 ${value}
List<Student> studentList = studentDao.findStudentByLikeName("小");
for (Student student:studentList){
System.out.println("student:"+student);
}
}
#{}vs${}区别?
#{}是获取参数中的属性值,并讲java中的类型转化为数据库中的类型
$ { } 为sql语句拼接,以${value} 获取参数中的值