对学习完的内容进行归纳总结-----------------
mvc: web开发中,使用mvc架构模式。 m:数据, v:视图, c:控制器。
mvc作用:
1)实现解耦合。
2)让mvc 各负其职。
3)使的系统扩展更好。更容易维护。
StudentService , OrderService, ShopService
StudentDao, OrderDao, ShopDao
等等。用户发起请求---->界面层----->业务逻辑层---->持久层---->数据库(mysql)
1,结构清晰、耦合度低, 各层分工明确
2,可维护性高,可扩展性高
3,有利于标准化
4,开发人员可以只关注整个结构中的其中某一层的功能实现
5,有利于各层逻辑的复用
每一层对应着一个框架
1)界面层—SpringMVC框架
2)业务层—Spring框架
3)持久层—MyBatis框架
1.什么是框架(framework)
框架:就是一个软件, 完成了部分的功能。 软件中的类和类之间的方法调用都已经规定好了。 通过这些可以完成某些功能。 框架看做是模版。
框架是可以升级的,改造的。 框架是安全的。
框架是对某一个方面有用的,不是全能的。
1)框架能实现技术的整合。
2)提供开发的效率。 降低难度。
优点:
缺点:
什么是 mybatis:
是一个持久层框架, 原名是ibatis, 2013改名为 MyBatis. MyBatis可以操作数据库,对数据执行增删改查。 看做是高级的jdbc。 解决jdbc的缺点。
mybatis能做什么?
1) 注册驱动 。
2) 创建jdbc中使用的Connection, Statement,ResultSet
3)执行sql语句, 得到ResultSet
4)处理ResultSet, 把记录集中的数据转为java对象, 同时还能把java对象放入到List集合。
5)关闭资源
6)实现sql语句和java代码的解耦合。
mybatis的文档: https://mybatis.org/mybatis-3/zh/index.html
加入资源插件1.自动提交:当你的 sql语句执行完毕后, 提交事务。 数据库更新操作之间保存到数据
2.手动(手工)提交事务:在你需要提交事务的位置, 执行方法,提交事务或者回顾事务。
1) Resources : mybatis框架中的对象, 一个作用读取主配置信息。
InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");
2)SqlSessionFactoryBuilder:负责创建SqlSessionFactory对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
3)SqlSessionFactory: 重要对象
SqlSessionFactory是重量级对象:创建此对象需要使用更多的资源和时间。 在项目中有一个就可以了。
SqlSessionFactory接口:作用是SqlSession的工厂, 就是创建SqlSession对象。
DefaultSqlSessionFactory实现类
public class DefaultSqlSessionFactory implements SqlSessionFactory {
}
SqlSessionFactory接口中的方法
openSession(): 获取一个默认的SqlSession对象, 默认是需要手工提交事务的。
openSession(boolean): boolean参数表示是否自动提交事务。
4)SqlSession对象
SqlSession对象是通过SqlSessionFactory获取的。 SqlSession本身是接口
DefaultSqlSession: 实现类
public class DefaultSqlSession implements SqlSession {
}
SqlSession作用是提供了大量的执行sql语句的方法:
selectOne:执行sql语句,最多得到一行记录,多余1行是错误。
selectList:执行sql语句,返回多行数据
selectMap:执行sql语句的,得到一个Map结果
insert:执行insert语句
update:执行update语句
delete:执行delete语句
commit:提交事务
rollback:回顾事务
注意SqlSession对象不是线程安全的, 使用的步骤:
①:在方法的内部,执行sql语句之前,先获取SqlSession对象
②:调用SqlSession的方法,执行sql语句
③:关闭SqlSession对象,执行SqlSession.close()
1)创建模版,mapper文件模版和mybatis主配置文件模版
创建模版的步骤:
创建文件选择使用的模版: 创建文件快捷键(Alt + insert)
mybatis创建Dao接口的实现类对象, 完成对sql语句的执行。
mybatis创建一个对象代替你的 dao实现类功能。
1)mapper文件中的namespace
一定dao接口的全限定名称
2)mapper文件中 标签的id是dao接口方法名称
使用SqlSession对象的方法 getMapper(dao.class)
例如: 现在有 StudentDao接口。
SqlSession session = MyBatisUtils.getSqlSession();
StudentDao dao = session.getMapper(StudentDao.class);
Student student = dao.selectById(1001);
//上面代码中
StudentDao dao = session.getMapper(StudentDao.class);
//等同于
StudentDao dao = new StudentDaoImpl();
理解参数是: 通过java程序把数据传入到mapper文件中的sql语句。
参数主要是指dao接口方法的形参
parameterType:表示参数的类型, 指定dao方法的形参数据类型。
这个形参的数据类型是给mybatis使用。 mybatis在给sql语句的参数赋值时使用。
PreparedStatement.setXXX( 位置, 值)
第一个用法: java类型的全限定类型名称 parameterType="java.lang.Integer"
第二个用法: mybatis定义的java类型的别名 parameterType="int"
parameterType:mybatis通过反射机制可以获取 dao接口方法参数的类型, 可以不写
<select id="selectById" parameterType="integer"
resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student where id=#{studentId}
select>
StudentDao.java
//dao接口的方法形参是一个简单类型的
//简单类型: java基本数据类型 和 String
Student selectByEmail(String email);
mapper文件:
<select id="selectByEmail" resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student where email=#{studentEmail}
select>
@Param
: 命名参数, 在方法的形参前面使用的, 定义参数名。 这个名称可以用在mapper文件中。
dao接口,方法的定义
/*多个简单类型的参数 使用@Param命名参数, 注解是mybatis提供的
位置:在形参定义的前面
属性:value 自定义的参数名称
*/
List<Student> selectByNameOrAge(@Param("myname") String name,
@Param("myage") Integer age);
mapper文件
<select id="selectByNameOrAge" resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student where name=#{myname} or age=#{myage}
select>
方法的形参是一个java对象。这个java对象表示多个参数。使用对象的属性值作为参数使用
java对象
public class Student {
private Integer id;
private String name;
private String email;
private Integer age;
//set|get方法
}
public class QueryParam {
private Object p1;
private Object p2;
//set|get方法
}
dao接口中的方法定义
/*
* 一个java对象作为参数( 对象由属性, 每个属性有set,get方法)
*/
List<Student> selectByObject(Student student);
List<Student> selectByQueryParam(QueryParam param);
mapper文件
<select id="selectByObject" resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student where name=#{name} or age=#{age}
select>
<select id="selectByQueryParam" resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student where name=#{p1} or age=#{p2}
select>
<select id="selectByObject" resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student where
name=#{name,javaType=java.lang.String,jdbcType=VARCHAR}
or
age=#{age,javaType=java.lang.Integer,jdbcType=INTEGER}
select>
参数位置: dao接口中方法的形参列表,从左往右,参数位置是 0 , 1, 2…
语法格式:#{arg0} ,#{arg1}
dao接口的方法
/*
使用位置,获取参数
*/
List<Student> selectByPosition(String name, Integer age);
<select id="selectByPosition" resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student where name=#{arg0} or age=#{arg1}
select>
map作为dao接口的参数, 使用 key 获取参数值,mapper文件中,语法格式 #{key}
/*
使用Map作为参数
*/
List<Student> selectStudentByMap(Map<String, Object> map);
mapper文件
<select id="selectStudentByMap" resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student where name=#{myname} or age=#{myage}
select>
测试,调用方法的位置
@Test
public void testSelectByMap(){
SqlSession session = MyBatisUtil.getSqlSession();
StudentDao dao = session.getMapper(StudentDao.class);
//使用map
HashMap<String, Object> data = new HashMap<>();
data.put("myname","王六六");
data.put("myage",19);
List<Student> students = dao.selectStudentByMap(data);
students.forEach(stu-> System.out.println("stu == " + stu));
session.close();
}
语法: #{字符}
mybatis处理#{}
使用jdbc对象是 PrepareStatment
对象
<select id="selectById" parameterType="integer"
resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student where id=#{studentId}
select>
mybatis处创建PrepareStatement对象,执行sql语句
String sql=" select id,name,email,age from student where id=?";
PrepareStatement pst = conn.prepareStatement(sql); pst.setInt(1,1001); //传递参数
ResultSet rs = pst.executeQuery(); //执行sql语句
#{}特点:
1)使用的PrepareStatement对象,执行sql语句,效率高。
2)使用的PrepareStatement对象,能避免sql注入, sql语句执行更安全。
3) #{} 常常作为 列值使用的, 位于等号的右侧, #{}位置的值和数据类型有关的。
语法 : ${字符}
mybatis执行${}占位符的sql语句
<select id="selectById" parameterType="integer"
resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student where id=${studentId}
select>
${} 表示字符串连接, 把sql语句的其他内容和 ${}内容使用 字符串(+) 连接的方式连在一起
String sql="select id,name,email,age from student where id=" + "1001";
//mybatis创建Statement对象, 执行sql语句。
Statement stmt = conn.createStatement(sql);
ResultSet rs = stmt.executeQuery();
${}
的特点
1)使用Statement对象,执行sql语句,效率低
2)${}
占位符的值,使用的字符串连接方式, 有sql注入的风险。 有代码安全的问题
3. ${}
数据是原样使用的, 不会区分数据类型。
4)${}
常用作 表名或者列名, 在能保证数据安全的情况下使用 ${}
封装输出结果: MyBatis执行sql语句,得到ResultSet, 转为java对象。
resultType属性: 在执行select时使用, 作为标签的属性出现的。
resultType:表示结果类型 , mysql执行sql语句,得到java对象的类型。
它的值有两种:
1) java类型的全限定名称 2)使用别名
1) resultType:表示java自定义对象
Student selectById(Integer id);
<select id="selectById" parameterType="integer"
resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student where id=#{studentId}
select>
resultType:现在使用java类型的全限定名称。
表示的意思 mybatis执行sql,把ResultSet中的数据转为Student类型的对象。
mybatis会做以下操作:
com.bjpowernode.domain.Student
的无参数构造方法,创建对象。Student student = new Student();
//使用反射创建对象所以执行 Student mystudent = dao.selectById(1001);
得到数据库中 id=1001这行数据,
这行数据的列值, 赋给了mystudent对象的属性。
能得到mystudent对象。 就相当于是 id=1001这行数据。
2)resultType表示简单类型
dao方法
long countStudent();
mapper文件
<select id="countStudent" resultType="java.lang.Long">
select count(*) from student
select>
3) resultType:表示一个map结构
//查询结果返回是一个
Map Map<Object,Object> selectMap(@Param("stuid") Integer id);
<select id="selectMap" resultType="java.util.HashMap">
select id,name,email from student where id != #{stuid}
select>
resultMap: 结果映射。 自定义列名和java对象属性的对应关系。 常用在列名和属性名不同的情况。
用法:
1.先定义 resultMap标签, 指定列名和属性名称对应关系
2.在select标签使用resultMap属性,指定上面定义的resultMap的id值
<resultMap id="customMap" type="com.bjpowernode.vo.CustomObject">
<id column="id" property="cid" />
<result column="name" property="cname" />
<result column="email" property="email" />
<result column="age" property="age" />
resultMap>
<select id="selectById2" resultMap="customMap">
select id,name,email,age from student where id=#{stuid}
select>
mybatis提供的对java类型定义简短,好记名称。
1)在mybatis主配置文件,使用 typeAliases标签声明别名
2)在mapper文件中, resultType=“别名”
声明别名(mybatis主配置文件)
<typeAliases>
<typeAlias type="com.bjpowernode.domain.Student" alias="stu" />
typeAliases>
mapper文件中使用
resultType="别名"
<select id="selectById" parameterType="integer" resultType="stu">
select id,name,email,age from student where id=#{studentId}
select>
1) 使用resultMap: 自定义列名和属性名称对应关系
2) 使用resultType: 使用列别名,让别名和java对象属性名称一样
第一种方式: 在java程序中,把like的内容组装好。 把这个内容传入到sql语句
List<Student> selectLikeOne(@Param("name") String name);
mapper
<select id="selectLikeOne" resultType="com.bjpowernode.domain.Student">
select * from student where name like #{name}
select>
执行like
@Test
public void testLikeOne(){
SqlSession sqlSession = MyBatisUtil.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
String name="%丸%";
List<Student> students = dao.selectLikeOne(name);
sqlSession.close();
students.forEach( stu-> System.out.println(stu));
}
第二种方式: 在sql语句,组织like的内容。
sql语句like的格式: where name like "%"空格#{name}空格"%"
List<Student> selectLikeTwo(@Param("name") String name);
<select id="selectLikeTwo" resultType="com.bjpowernode.domain.Student">
select * from student where name like "%" #{name} "%"
select>
@Test
public void testLikeTwo(){
SqlSession sqlSession = MyBatisUtil.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
String name="丸";
List<Student> students = dao.selectLikeTwo(name);
sqlSession.close();
students.forEach( stu-> System.out.println(stu));
}
什么是动态sql: 同一个dao的方法, 根据不同的条件可以表示不同的sql语句, 主要是where
部分有变化
使用mybatis提供的标签,实现动态sql的能力, 主要讲 if ,where ,foreach, sql。
使用动态sql的时候, dao方法的形参使用java对象。
语法:
<if test="boolean判断结果">
sql 代码
if>
在mapper文件中
<select id="selectStudent" resultType="com.bjpwoernode.domain.Student">
select *from student
<if test="条件">
sql语句
if>
<if test="条件">
sql语句
if>
select>
例子:
List<Student> selectIf(Student student);
<select id="selectIf" resultType="com.bjpowernode.domain.Student">
<include refid="selectStudent" />
where
<if test="name !=null and name!=''">
name = #{name}
if>
<if test="age >0">
-- or age < #{age}
or age = #{age}
if>
select>
使用if标签时,容易引起sql语句语法错误。 使用where标签解决if产生的语法问题。
使用时 where ,里面是一个或多个if 标签, 当有一个if标签 判断条件为true, where标签会转为 WHERE 关键字附加到sql语句的后面。 如果 if 没有一个条件为true , 忽略where和里面的if。
where标签删除 和他最近的or 或者 and。
语法:
<where>
<if test="条件1">sql语句1if>
<if test="条件2">sql语句2if>
where>
例子:
List<Student> selectWhere(Student student);
<select id="selectWhere" resultType="com.bjpowernode.domain.Student">
select * from student
<where>
<if test="name !=null and name!=''">
or name = #{name}
if>
<if test="age >0">
or age < #{age}
if>
where>
select>
使用foreach可以循环数组,list集合, 一般使用在in语句中。
语法:
< foreach collection="集合类型" open="开始的字符" close="结束的字符"
item="集合中的成员" separator="集合成员之间的分隔符">
#{item 的值}
foreach>
标签属性:
collection: 表示,循环的对象是 数组, 还是list集合。 如果dao接口方法的形参是 数组, collection=“array” ,如果dao接口形参是List, collection=“list”
open:循环开始时的字符。 sql.append("(");
close:循环结束时字符。 sql.append(")");
item:集合成员, 自定义的变量。
Integer item = idlist.get(i);// item是集合成员 separator:集合成员之间的分隔符。
sql.append(","); //集合成员之间的分隔符
#{
item 的值}:获取集合成员的值。
第一种方式:
//foreach-1
List<Student> selectForeachOne(List<Integer> idlist);
<select id="selectForeachOne" resultType="com.bjpowernode.domain.Student">
select * from student
<if test="list !=null and list.size>0">
where id in
<foreach collection="list" open="(" close=")" separator="," item="myid">
#{myid}
foreach>
if>
select>
@Test
public void testSelectForeachOne(){
//1.获取SqlSession
SqlSession session = MyBatisUtil.getSqlSession();
//2.获取dao的代理
StudentDao dao = session.getMapper(StudentDao.class);
List<Integer> idlist = new ArrayList<>();
idlist.add(1001);
idlist.add(1002);
idlist.add(1003);
List<Student> students = dao.selectForeachOne(idlist);
students.forEach( stu-> System.out.println("stu=="+stu));
//3.关闭SqlSession对象
session.close();
}
第二种方式:
//foreach-2
List<Student> selectForeachTwo(List<Student> studentList);
<select id="selectForeachTwo" resultType="com.bjpowernode.domain.Student">
select * from student
<if test="list != null and list.size > 0 ">
where id in
<foreach collection="list" open="(" close=")" separator="," item="stu">
#{stu.id}
foreach>
if>
select>
@Test
public void testSelectForeachTwo(){
//1.获取SqlSession
SqlSession session = MyBatisUtil.getSqlSession();
//2.获取dao的代理
StudentDao dao = session.getMapper(StudentDao.class);
List<Student> list = new ArrayList<>();
Student s1 = new Student();
s1.setId(1001);
Student s2 = new Student();
s2.setId(1005);
list.add(s1);
list.add(s2);
List<Student> students = dao.selectForeachTwo(list);
students.forEach( stu-> System.out.println("stu=="+stu));
//3.关闭SqlSession对象
session.close();
}
sql标签标示 一段sql代码, 可以是表名,几个字段, where条件都可以, 可以在其他地方复用sql标签的内容。
使用方式:
1)在mapper文件中定义 sql代码片段
2)在其他的位置,使用include标签引用某个代码片段
例如:
<sql id="selectStudent">
select * from student
sql>
<sql id="studentFieldList">
id,name,email
sql>
<select id="selectIf" resultType="com.bjpowernode.domain.Student">
<include refid="selectStudent" />
where
<if test="name !=null and name!=''">
name = #{name}
if>
<if test="age >0">
-- or age < #{age}
or age = #{age}
if>
select>
<select id="selectWhere" resultType="com.bjpowernode.domain.Student">
select <include refid="studentFieldList"/> from student
<where>
<if test="name !=null and name!=''">
or name = #{name}
if>
<if test="age >0">
or age < #{age}
if>
where>
select>
mybatis配置文件两大类: 1 mybatis主配置文件; 2 mybatis的mapper文件
settings是mybatis的全局设置,影响整个mybatis的运行。 这个设置一般使用默认值就可以了。
<settings>
<setting name="cacheEnabled" value="true"/>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="multipleResultSetsEnabled" value="true"/>
<setting name="useColumnLabel" value="true"/>
<setting name="useGeneratedKeys" value="false"/>
<setting name="autoMappingBehavior" value="PARTIAL"/>
<setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
<setting name="defaultExecutorType" value="SIMPLE"/>
<setting name="defaultStatementTimeout" value="25"/>
<setting name="defaultFetchSize" value="100"/>
<setting name="safeRowBoundsEnabled" value="false"/>
<setting name="mapUnderscoreToCamelCase" value="false"/>
<setting name="localCacheScope" value="SESSION"/>
<setting name="jdbcTypeForNull" value="OTHER"/>
<setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/> settings>
设置别名
<typeAliases>
<package name="com.bjpowernode.domain" />
<package name="com.bjpowernode.vo" />
typeAliases>
environments: 环境标签, 在他里面可以配置多个environment
属性: default ,必须是某个environment的id属性值。 表示mybatis默认连接的数据库
environment: 表示一个数据库的连接信息。
属性: id 自定义的环境的标识。 唯一值。
transactionManager:事务管理器 属性: type 表示事务管理器的类型。
属性值:
1)JDBC: 使用Connection对象, 由mybatis自己完成事务的处理。
2) MANAGED: 管理,表示把事务的处理交给容器实现(由其他软件完成事务的提交,回滚)
dataSource: 数据源,创建的Connection对象,连接数据库。
属性: type 数据源的类型
属性值:
1) POOLED, mybatis会在内存中创建PooledDataSource类,管理多个Connection连接对象,使用的连接池
2) UNPOOLED ,不使用连接池, mybatis创建一个UnPooledDataSource这个类, 每次执行sql 语句先创建Connection对象, 再执行sql语句,最后关闭Connection
3)JNDI : java的命名和目录服务。
<environments default="online">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url"
value="jdbc:mysql://localhost:3306/springdb?useUnicode=true&characterEncoding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="666666"/>
dataSource>
environment>
<environment id="online">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/springdb"/>
<property name="username" value="admin"/>
<property name="password" value="123456"/>
dataSource>
environment>
environments>
需要把数据库的配置信息放到一个单独文件中, 独立管理。 这个文件扩展名是 properties. 在这个文件中,使用自定义的key=value的格式表示数据
使用步骤:
1.在resources目录中,创建xxxx.properties
2.在文件中,使用 key=value的格式定义数据。
例如 jdbc.url=jdbc:mysq://localhost:3306/springdb
3.在mybatis主配置文件, 使用properties标签引用外部的属性配置文件
4.在使用值的位置, 使用${key}获取key对应的value(等号右侧的值)
例子:
jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/springdb?useUnicode=true&characterEncoding=utf-8
jdbc.username=root
jdbc.password=123
mybatis主配置文件
<properties resource="jdbc.properties" />
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url"
value="jdbc:mysql://localhost:3306/springdb?useUnicode=true&characterEncoding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="666666"/>
dataSource>
environment>
environments>
使用mapper指定其他mapper文件的位置,
mapper标签使用的格式有两个常用的方式:
<mappers>
<mapper resource="com/bjpowernode/dao/StudentDao.xml"/>
<mapper resource="com/bjpowernode/dao/OrderDao.xml"/>
<package name="com.bjpowernode.dao" />
<package name="com.bjpowernode.dao1" />
mappers>
PageHelper做数据分页。 在你的select语句后面加入 分页的 sql 内容, 如果你使用的mysql数据库, 它就是在select * from student 后面加入 limit 语句。
使用步骤:
在mybatis.xml的configuration标签中看顺序如下:
<!ELEMENT configuration (properties?, settings?, typeAliases?, typeHandlers?, objectFactory?, objectWrapperFactory?, reflectorFactory?, plugins?, environments?, databaseIdProvider?, mappers?)>
1.加入依赖pagehelper依赖
<dependency>
<groupId>com.github.pagehelpergroupId>
<artifactId>pagehelperartifactId>
<version>5.1.10version>
dependency>
2.在mybatis主配置文件, 加入plugin声明
在<environments> 之前加入
<plugins>
<plugin interceptor ="com.github.pagehelper.PageInterceptor" />
plugins>
3.在select语句之前,调用PageHelper.startPage(页码, 每页大小)
对比:
没有使用PageHelper
select * from student order by id
使用PageHelper
SELECT count(0) FROM student
select * from student order by id LIMIT ?