注意:所有文章除特别说明外,转载请注明出处.
Mybatis - FD
前言
1.原生态JDBC程序存在问题
public static void main(String[] args) {
//设置连接为null
Connection connection = null;
//设置预处理状态为null
PreparedStatement preparedStatement = null;
//设置结果集为null
ResultSet resultSet = null;
//检查异常并抛出异常
try {
//1、加载数据库驱动
Class.forName("com.mysql.jdbc.Driver");
//2、通过驱动管理类获取数据库链接
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8", "root", "root");
//3、定义sql语句 ?表示占位符
String sql = "select * from user where username = ?";
//4、获取预处理statement
preparedStatement = connection.prepareStatement(sql);
//5、设置参数,第一个参数为sql语句中参数的序号(从1开始),第二个参数为设置的参数值
preparedStatement.setString(1, "Aaron");
//6、向数据库发出sql执行查询,查询出结果集
resultSet = preparedStatement.executeQuery();
//7、遍历查询结果集
while(resultSet.next()){
System.out.println(resultSet.getString("id")+" "+resultSet.getString("username"));
}
} catch (Exception e) {
e.printStackTrace();
}finally{
//8、释放资源
if(resultSet!=null){
try {
resultSet.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(preparedStatement!=null){
try {
preparedStatement.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(connection!=null){
try {
connection.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
总结:1.JDBC在使用过程中数据库连接会频繁开启和关闭,会严重影响到数据库的性能。2.在程序中存在硬编码,数据库部分以及SQL执行部分。
Mybatis 框架原理
1.mybatis配置文件,包括Mybatis全局配置文件和Mybatis映射文件,其中全局配置文件配置了数据源、事务等信息。映射文件配置了SQL执行相关的信息。
2.mybatis通过读取配置文件信息(全局配置文件和映射文件),构造出SqlSessionFactory,即会话工厂(sqlSessionFactory)。
3.通过SqlSessionFactory(会话工厂),可以创建SqlSession即会话。Mybatis是通过SqlSession来操作数据库的。
4.SqlSession(会话)其本身不能直接操作数据库,它是通过底层的Executor执行器接口来操作数据库的。Executor接口有两个实现类,一个是普通执行器,一个是缓存执行器(默认)。
5.Executor执行器要处理的SQL信息是封装到一个底层对象 MappedStatement 中。该对象包括:SQL语句、输入参数映射信息、输出结果集映射信息。其中输入参数和输出结果的映射类型包括Java的简单类型、HashMap集合对象、POJO对象类型。
Mybatis 入门程序
1.实现步骤
1.创建数据表
2.添加相关依赖文件
3.添加log4j.properties文件(因为mybatis使用的日志包是log4j(在classpath路径下创建该文件))
# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
注意:日志级别在开发阶段设置成DEBUG,在生产阶段设置成INFO或者ERROR。
4.编程步骤
1.创建PO类,根据需求创建
Public class User {
private int id;
private String username;// 用户姓名
private String sex;// 性别
private Date birthday;// 生日
private String address;// 地址
//以及一系列的get/set方法
}
注意:创建的po类属性名称应该和数据库表中的列名一致,如果表中的列名带有下划线,那么PO类中对应的属性名要采用驼峰式命名。驼峰式命名:骆驼式命名法就是当变量名或函数名是由一个或多个单词连结在一起,而构成的唯一识别字时,第一个单词以小写字母开始;从第二个单词开始以后的每个单词的首字母都采用大写字母,例如:myFirstName、myLastName,这样的变量名看上去就像骆驼峰一样此起彼伏,故得名。
2.创建全局配置文件SqlMapConfig.xml(是在classpath路径下创建配置文件)
<?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">
<configuration>
<!-- 配置mybatis的环境信息 -->
<environments default="development">
<environment id="development">
<!-- 配置JDBC事务控制,由mybatis进行管理 -->
<transactionManager type="JDBC"></transactionManager>
<!-- 配置数据源,采用dbcp连接池 -->
<dataSource type="POOLED">
<!—驱动和URL设置-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
</configuration>
3.编写映射文件(xxxMapper.xml(mapper接口的实现类))
<?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">
4.加载映射文件,在SqlMapConfig.xml中进行加载
<!-- 加载mapper -->
<mappers>
<mapper resource="sqlmap/User.xml"/>
</mappers>
5.编写测试程序,即编写Java代码,连接并操作数据库
public class MybatisFirst {
@Test
public void findUserByIdTest() throws Exception{
//1、读取配置文件
String resource = "SqlMapConfig.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
//2、根据配置文件创建SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//3、SqlSessionFactory创建SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
//4、SqlSession执行statement,并返回映射结果
//第一个参数:statement的id,建议:namespace.statementId(确保唯一)
//第二个参数:入参的值,它的类型要和映射文件中对应的statement的入参类型一致
User user = sqlSession.selectOne("findUserById", 1);
//打印输出结果集
System.out.println(user);
//5、关闭SqlSession
sqlSession.close();
}
}
总结:1.首先读取配置文件,然后通过SqlSessionFactoryBuilder创建SqlSessionFactory会话工厂。
2.通过SqlSessionFactory创建SqlSession,然后调用SqlSession的操作数据库的方法。
3.最后关闭SqlSession。
小结
1.parameterType 指定输入参数的Java类型,可以填写别名或Java类的全限定名。
2.resultType 指定输出结果的Java类型,可以填写别名或Java类的全限定名。
#{}和${}
#{}:相当于预处理中的占位符?。
#{}里面的参数表示接收java输入参数的名称。
#{}可以接受HashMap、简单类型、POJO类型的参数。
当接受简单类型的参数时,#{}里面可以是value,也可以是其他。
#{}可以防止SQL注入。
${}:相当于拼接SQL串,对传入的值不做任何解释的原样输出。
${}会引起SQL注入,所以要谨慎使用。
${}可以接受HashMap、简单类型、POJO类型的参数。
当接受简单类型的参数时,${}里面只能是value。
selectOne:只能查询0或1条记录,大于1条记录的话,会报错
selectList:可以查询0或N条记录
Mybatis 开发DAO
我们知道,mybatis在项目开发中主要使用的地方就是开发DAO(数据访问层)。所以开发方式有两种。1.原始的DAO开发方式。2.Mapper代理开发方式。
1.原始DAO开发方式
实现步骤:
1.根据需求创建po类
这一步骤的实现所对应的属性名要与数据库中的属性名相对应
2.编写全局配置文件
这一步骤的实现是配置数据源等信息
3.根据需求编写映射文件
实现实体类与数据库之间的数据操作
4.加载映射文件
5.编写dao接口
public interface UserDao {
//根据用户ID来查询用户信息
public User findUserById(int id);
//根据用户名称来模糊查询用户信息列表
public List<User> findUsersByName(String username);
//添加用户
public void insertUser(User user);
}
6.编写dao实现类
public class UserDaoImpl implements UserDao {
//注入SqlSessionFactory
private SqlSessionFactory sqlSessionFactory;
//使用构造方法来初始化SqlSessionFactory
public UserDaoImpl(SqlSessionFactory sqlSessionFactory){
this.sqlSessionFactory = sqlSessionFactory;
}
@Override
public User findUserById(int id) {
//通过工厂,在方法内部获取SqlSession,这样就可以避免线程不安全
SqlSession sqlSession = sqlSessionFactory.openSession();
//返回结果集
return sqlSession.selectOne("test.findUserById", id);
}
@Override
public List<User> findUsersByName(String username) {
//通过工厂,在方法内部获取SqlSession,这样就可以避免线程不安全
SqlSession sqlSession = sqlSessionFactory.openSession();
return sqlSession.selectList("test.findUsersByName", username);
}
@Override
public void insertUser(User user) {
//通过工厂,在方法内部获取SqlSession,这样就可以避免线程不安全
SqlSession sqlSession = sqlSessionFactory.openSession();
sqlSession.insert("test.insertUser", user);
}
}
7.编写测试代码
public class UserDaoTest {
//声明全局的SqlSessionFactory
private SqlSessionFactory sqlSessionFactory;
@Before
//此方法在测试方法执行之前执行,spring开发方式
public void setUp() throws Exception {
// 1、读取配置文件
String resource = "SqlMapConfig.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
// 2、根据配置文件创建SqlSessionFactory
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void testFindUserById() {
//构造UserDao对象
UserDao userDao = new UserDaoImpl(sqlSessionFactory);
//调用UserDao对象的方法
User user = userDao.findUserById(1);
System.out.println(user);
}
@Test
public void testFindUsersByName() {
//构造UserDao对象
UserDao userDao = new UserDaoImpl(sqlSessionFactory);
//调用UserDao对象的方法
List<User> list = userDao.findUsersByName("小明");
System.out.println(list);
}
@Test
public void testInsertUser() {
//构造UserDao对象
UserDao userDao = new UserDaoImpl(sqlSessionFactory);
//构造User对象
User user = new User();
user.setUsername("东哥3");
user.setAddress("清河宝盛西里3");
//调用UserDao对象的方法
userDao.insertUser(user);
System.out.println(user.getId());
}
}
2.mapper开发代理方式
使用Mapper代理的开发方式,我们只需要编写mapper接口,然后mybatis会自动为mapper接口生成动态代理实现类。
1.mapper接口的全限定名要和mapper映射文件的namespace的值相同。
2.mapper接口的方法名称要和mapper映射文件中的statement的id相同。
3.mapper接口的方法参数只能有一个,且类型要和mapper映射文件中statement的parameterType的值保持一致。
4.mapper接口的返回值类型要和mapper映射文件中statement的resultType值或resultMap中的type值保持一致。
提示:statement表示Java执行数据库操作的一个重要接口,用于在已经建立的数据库连接的基础上,向数据库发送要执行的SQL语句,Statement对象用于执行不带参数的简单SQL语句。
Mybatis 映射文件
1.输入映射
ParameterType
2.输出映射
resultType
3.高级映射
resultMap
mybatis 高级映射
1.mybatis框架执行过程:
1.配置mybatis的配置文件(mybatis-config.xml)(名称不固定)。
2.通过配置文件(mybatis-config.xml),加载mybatis运行环境,创建SqlSessionFactory会话工厂,SqlSessionFactory在实际使用时按单例方式。
3.通过SqlSessionFactory创建SqlSession,SqlSession是一个面向用户接口(提供操作数据库方法),实现对象是线程不安全的,建议sqlSession应用场合在方法体内。
4.调用sqlSession的方法去操作数据。如果需要提交事务,需要执行SqlSession的commit()方法。
5.释放资源,关闭SqlSession
2.mybatis开发dao的方法
1.使用原始的dao的方法
这样需要编写dao接口和实现类,需要在dao实现类注入一个SqlSessionFactory工厂。
2.mapper代理开发方法(推荐)
0.编写mapper接口(dao接口)
注意:在编写mapper.xml(映射文件)和mapper.java(接口)需要遵循开发规范
1.mapper.xml中的namespace就是mapper.java的类的全路径名
2.mapper.xml中statement的id值和mapper.java中方法名一致(如:insert/delete/update中的id值)
3.mapper.xml中statement的parameterType指定输入参数的类型和mapper.java的方法数据参数类型一致(parameterType类型与对应的接口方法参数类型一致)
4.mapper.xml中statement的resultType指定输出结果的类型和mapper.java的方法返回值类型一致(resultMap:定义出参,调用已经定义的<resultMap></resultMap>映射管理器的id值
resultType:定义出参,匹配普通Java类型或自定义pojo类型(出参类型若不指定,将为语句默认类型))
注意:全局配置文件(mybatis-config.xml)可以配置properties属性、别名、mapper加载等。
3.输入映射
1.parameterType:指定输入参数类型可以是简单类型、POJO、HashMap,而对于综合查询,建议parameterType使用包装的pojo,有利于系统扩展。
4.输出映射
1.resultType:查询到的列名和resultType指定的POJO的属性名一致,这样才能映射成功。
作用:将查询结果按照sql列名pojo属性名一致性映射到pojo中
场合:
2.resultMap:可以通过resultMap完成高级映射,如果查询到的列名和映射的POJO的属性名不一致时,通过resultMap设置别名和属性名之间的对应关系(映射关系),可以完成映射。
association
作用:将关联查询信息映射到一个pojo对象中
场合:为了方便查询关联信息可以使用association将关联 订单信息 映射为 用户对象 的pojo属性中。association适用于一对一查询。
注意:使用resultType无法将查询结果映射到pojo对象的pojo属性中,根据对结果集查询遍历的需要选择使用resultType还是resultMap
collection
作用:将关联查询信息映射到一个list集合中
场合:为了方便查询遍历关联信息可以使用collection将关联信息映射到list集合中,而如果使用resultType无法将查询结果映射到list集合中。collection适用于一对多和多对多的查询。
扩展:映射管理器
resultMap
:是mybatis
中强大的工具,使用其可以进行 实体类之间 的映射,并且管理 结果和实体类 之间的映射关系。
resultMap映射管理器需要配置的属性:
<resultMap id="" type=""></resutlMap>
id=" ":表示这个映射管理器的唯一标识,外部通过该值引用
type = " ":表示需要映射的实体类
resultMap映射管理器需要配置的参数:
<id column = " " property= " " />
<id>标签指的是:结果集中结果唯一的列column(column:指定唯一标识用户信息的数据列)和实体属性property(property:映射到user实体类的哪个属性)的映射关系
注意:<id>标签管理的列未必是主键列,需要根据具体需求指定
<result column= " " property=" " />
<result>标签指的是:结果集中普通列column和实体属性property的映射关系
resultMap映射管理器需要维护的关系:所谓关系维护是值在 主表查询时将其关联子表的结果也查询出来
resultMap元素中,允许有如下直接子元素:
1.constructor:类在实例化时,用来注入结果到构造方法中,作用与result相同,同时可以标识出用这个字段值可以区分其他对象实例
arg:注入到构造方法的一个普通结果
idArg:ID参数,标记结果作为ID,可以帮助提高整体效能
2.result:将数据表中的字段注入到Java对象属性中
3.association:关联(一对一的关系),表示在resultMap映射器中,通过<association></association>进行维护,在查询一个对象时,可以将关联的对应信息也查询出来。
作用:将关联查询的信息映射到一个POJO中
<association property="" javaType="">
property:对象属性的名称,被维护实体在宿主实体(POJO)中的属性名
javaType:对象属性的类型,被维护实体的类型
column:所对应的外键字段名称
select:使用另一个查询封装的结果
4.collection:集合(一对多/多对多关系的维护),对关联查询到的多条记录映射到集合对象中。
作用:将关联查询用户信息映射到一个list集合中
<collection property="" ofType="">
property="" 将查询到的多条记录映射到相应的POJO类上对应的属性中
ofType="" 指定映射到List集合的pojo类型
5.discriminator:使用结果集决定使用哪个个结果映射
拓展:sql片段标签
:通过该标签可定义能复用的sql语句片段,在执行sql语句标签中直接引用。
注意:需要配置的属性,id="" 表示需要改sql语句片段的唯一标识 引用:通过<include refid=""/>标签引用,refid=""中的值指向需要引用的<sql>中的id=""属性。
注意:在resultMap中应该注意两点
1.关联关系的维护可以根据实体类之间的实际情况进行嵌套维护
2.出现重复列名的处理,在实际操作过程中,查询到的结果可能会出现相同的列名,这样会对映射到实体属性带来影响甚至报错,所以可以通过对列取别名的方式来处理
5.高级映射
1.将关联查询的列映射到一个POJO属性中(一对一)
2.将关联查询的列映射到一个List
mybatis动态sql语句
6.常用的动态语句标签(通过动态sql标签可以进行条件判断,条件遍历等操作从而能够满足结果中的需要)
<where>:这一标签的使用可以代替sql语句中的where关键字,一般放置在条件查询的最外层
where后面跟查询条件,简化sql语句中判断条件的书写 此中,mybatis会智能的将首个and或or给忽略
<if>:这一标签配置属性test="条件字符串",判断是否满足条件
<set>:这一标签常用于<update>更新语句中,替代sql的set关键字,特别是在联合<if>进行判断是否条件时,可以有效方式当某个参数为空或者不合法是错误的更新到数据库中
mybatis set标签的使用:sql语句中的最后一个逗号会被set标记自动忽略
<trim>:在mapper.xml中对statement的定义,可以使用<trim>标签来填充和隐藏sql语句。
功能:1.如果标签体中有SQL语句,就把修饰后的SQL语句拼接到之前的SQL语句上,如果标签体中没有SQL语句,那么这标签相当于不存在。2.这四个属性的默认值都是空字符串。
trim属性 prefix:前缀 suffix:后缀
<trim prefix="(" suffix=")" prefixOverrides="," suffixOverrides=",">
属性:
1.prefix="(" 在trim标签定义的内容前填充对应内容
2.suffix=")" 在trim标签定义的内容后填充对应内容
3.prefixOverrides="," 在trim定义的中,隐藏头部对应的内容。这个属性指定一个字符串,这个字符串一定是SQL语句的前缀,如果不是前缀,这个属性不起作用。会用prefix属性指定的字符串替换掉这个属性指定的字符串。
4.suffixOverrides="," 在trim定义的中,隐藏尾部对应的内容。这个属性指定一个字符串,这个字符串位一定是SQL语句的后缀,如果不是后缀,这个属性不起作用。其会用suffix属性指定的字符串替换这个属性指定的字符串。
标签组:
<choose>
<when> //此元素的作用与Java中的switch效果差不多
</when>
<otherwise>
</otherwise>
</choose>
也是一个用于条件判断的标签组,和<if>的不同之处在于条件从<choose>进入,去匹配<when>中的添加,一旦匹配马上结束,若到找不到匹配项,将执行<otherwise>中的语句;可以理解为<if>是 && 关系 <choose>是 || 关系
<foreach>标签:遍历集合类型的条件(在实现 mybatis in 语句查询时特别有用)
属性:collection="array/list" 是数组类型还是集合类型
item=" " 参数名
open="(" separator="," close=")" 开始符号,分隔符号,结束符号
index="" 结束下标位置,不配置该参数时,默认为全部遍历
扩展:
MySQL JOIN语法
join用于多表中字段之间的联系(...FROM table1(左表) INNER|LEFT|RIGHT JOIN table2(右表) ON condition)
大致功能:
1.INNER JOIN(内连接 取两表的交集):取得两个表中存在连接匹配关系的记录(产生一组同时符合A和B的数据)
2.LEFT JOIN(左连接):取得左表(table1)完全记录,即是右表(table2)并无对应匹配记录
3.RIGHT JOIN(右连接):与 LEFT JOIN 相反,取得右表(table2)完全记录,即是左表(table1)并无匹配对应记录
条件ON与Where的执行顺序
ON:用来决定如何从B表中检索数据行
mybatis高级查询
1.关联查询
在查询一个结果的时候,查询出其他关联的结果集
2.子查询
关联查询一般可以使用子查询来实现,但是一般情况下子查询的效率低于关联查询
3.集合查询
集合查询是关联查询的一种,只不过它是一对多而已
4.mapper.xml源码分析
1.namespace:对应mapper接口(类似dao接口)
2.resultMap:
1.id:
5.一对一查询(resultType 实现)
使用resultType来进行一对一结果映射,查询出的列的个数和映射的属性的个数要一致。而且映射的属性要存在与一个大的对象中,它是一种平铺式的映射,即数据库查询出多少条记录,则映射成多少个对象。
一对一查询(resultMap 实现)
使用resultMap来进行一对一结果映射,它是将关联对象添加到主信息的对象中,具体说是一种对象嵌套另一种对象的一种映射方式。
<resultMap type="mybatis.po.OrdersExt" id="OrdersAndUserRstMap">
<!-- 订单信息 -->
<id column="id" property="id"/>
<result column="user_id" property="userId"/>
<result column="number" property="number"/>
<!-- 对象嵌套映射 -->
<!-- association:一对一关联映射 -->
<!-- property:关联信息查询的结果将要映射的扩展类中的对象属性名称 -->
<!-- id标签:建议在关联查询时必须写上,不写不会报错,但是会影响性能 -->
//association:表示在resultMap映射器中,通过<association>进行维护,在查询一个对象时,可以将关联的对应信息也查询出来
<association property="user" javaType="mybatis.po.User">
<id column="user_id" property="id"/>
<result column="username" property="username"/>
<result column="sex" property="sex"/>
</association>
总结:在一对一映射结果时,使用
resultType
更加简单方便,如果有特殊要求(对象嵌套对象)时,需要使用resultMap
进行映射,关联查询出其关联信息。
6.一对多查询
1.多对一的查询引入association,进行联合查询
<resultMap id="resultUserArticleList" type="Article">
<id property="id" column="aid" />
<result property="title" column="title" />
<result property="content" column="content" />
<association property="user" javaType="User">
<id property="id" column="id" />
<result property="userName" column="userName" />
<result property="userAddress" column="userAddress" />
</association>
</resultMap>
<select id="getUserArticles" parameterType="int" resultMap="resultUserArticleList">
select user.id,user.userName,user.userAddress,article.id aid,article.title,article.content from user,article where user.id=article.userid and user.id=#{id}
</select>
总结:在上述配置之后,将select语句与resultMap对应的映射结合起来,可以看出,用association来得到关联的用户,得到的所有文章都是同一个用户的。
2.复用已经定义好的resultMap,将association中对应的映射独立抽取出来,以至于能够达到复用的目的
1.首先定义好一个resultMap
<resultMap type="User" id="resultListUser">
<id column="id" property="id" />
<result column="userName" property="userName" />
<result column="userAge" property="userAge" />
<result column="userAddress" property="userAddress" />
</resultMap>
2.然后在新定义的resultMap中引用已定义的resultMap
<resultMap id="resultUserArticleList-2" type="Article">
<id property="id" column="aid" />
<result property="title" column="title" />
<result property="content" column="content" />
<association property="user" javaType="User" resultMap="resultListUser" /> //在这里使用association复用已经定义好的resultMap
</resultMap>
7.多对多映射查询(只是一对多映射的特例)
多对多映射查询只不过是一对多映射的特例,其是在一对多的基础上添加多个<collection>来表明多个数据表单之间的关系的。
如:
1.定义resultMap
<!-- 查询用户即购买的商品信息的ResultMap -->
<resultMap type="com.mybatis.entity.User" id="userAndItemsResultMap">
<!-- 用户信息 -->
<id column="user_id" property="id"/>
<result column="username" property="username"/>
<result column="sex" property="sex"/>
<result column="address" property="address"/>
<!-- 订单信息
一个用户对应多个订单,使用collection映射
在用户信息中关联映射商品订单信息-->
<collection property="ordersList" ofType="com.mybatis.entity.Orders">
<id column="id" property="id"/>
<result column="user_id" property="userid"/>
<result column="number" property="number"/>
<result column="createtime" property="createTime"/>
<result column="note" property="note"/>
<!-- 订单明细
一个订单包括多个明细
在商品订单中关联映射商品订单的多个明细
-->
<collection property="orderdetails" ofType="com.mybatis.entity.OrderDetail">
<id column="orderdetail_id" property="id"/>
<result column="items_id" property="itemsId"/>
<result column="items_num" property="itemsNum"/>
<result column="orders_id" property="ordersId"/>
<!-- 商品信息
一个订单明细对应一个商品
然后这儿是一对一的关联映射,所以使用的association进行两者之间的映射
-->
<association property="items" javaType="com.mybatis.entity.Items">
<id column="items_id" property="id"/>
<result column="items_name" property="itemsName"/>
<result column="items_detail" property="detail"/>
<result column="items_price" property="price"/>
</association>
</collection>
</collection>
</resultMap>
<!-- 查询用户及用户购买的商品信息,使用resulaMap-->
2.定义statement(statement表示Java执行数据库操作的一个重要接口,用于在已经建立的数据库连接的基础上向数据库发送要执行的SQL语句,Statement用于执行不带参数的简单SQL语句)
<select id="findUserAndItemsResultMap" resultMap="userAndItemsResultMap">
SELECT
t1.*,
t2.username,
t2.sex,
t2.address,
t3.id orderdetail_id,
t3.items_id,
t3.items_num,
t3.orders_id,
t4.itemsname items_name,
t4.detail items_detail,
t4.price items_price
FROM
orders t1,
t_user t2,
orderdetail t3,
items t4
WHERE t1.user_id = t2.id AND t3.orders_id=t1.id AND t3.items_id = t4.id
</select>
扩展
为了验证上述得到的结果是否正确,可以对其进行junit测试。
public class OrdersCustomMapperTest {
//创建会话工厂
private SqlSessionFactory sqlSessionFactory;
//查询订单,关联查询用户信息,使用resultType实现的测试
@Test
public void TestFindOrdersUser() {
//利用会话工厂创建会话
SqlSession sqlSession = sqlSessionFactory.openSession();
// 创建代理对象
OrdersCustomMapper oc = sqlSession.getMapper(OrdersCustomMapper.class);
// 调用mapper接口中的方法
List<OrdersCustom> list = oc.findOrdersUser();
//作为验证是否输出的list是否和要查询的结果正确
System.out.println(list);
//关闭会话
sqlSession.close();
}
mybatis开发总结
1.一般的查询直接返回实体类型即可,而对于关联查询,处理方式之一就是:自己构造一个resultMap,名称为Map1。然后将自己所需要的字段在新建的resultMap中做一个映射,然后将查询结果设置为新建的Map1。
注意:在Map1中可以多映射一些字段,为空的查询默认不映射
2.在Mapper层接口,我们一般设置该方法的返回值类型是:List<Map<String,Object>> 每一个list里面放有很多的map键值对
3.#{} 表示一个占位符,通过#{}可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换,此外,#{}可以有效防止sql注入
${} 表示拼接sql串,通过${}可以将parameterType传入的内容拼接在sql中不进行jdbc类型转换
4.mybatis解决JDBC编程问题
1.在SqlMapConfig.xml中配置数据库连接池管理数据库连接可以解决因为数据库频繁创建、释放连接而影响系统性能的问题
2.模糊查询,resultType:表示是List的泛型类型 ${value} 固定写法只能写value表示拼接字符串
Mybatis整合Spring
1.整合思路:
1.数据源信息交给Spring管理
2.SqlSessionFactory交给Spring进行单例管理
3.由Spring来管理原始DAO的实现类或者Mapper代理的代理类
2.1 具体整合步骤1:
1.Mybatis
1.在配置文件文件夹(config)下创建SqlMapConfig.xml
2.配置属性文件(db.properties/log4j.properties)
注意:mybatis的配置文件中的数据源配置去掉,由spring进行管理配置。
2.Spring
1.在配置文件文件夹(config)下创建application.xml
1.加载Java的配置文件
<context:property-placeholder location="db.properties">
2.创建数据源
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
//将数据库的驱动(driverClassName)、URL、username、password、maxActive、maxIdle属性值配置完
3.配置SqlSessionFactory
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
//1.指定mybatis的全局配置文件路径
<property name="configLocation" value="mybatis/SqlMapConfig.xml">
//2.配置数据源
<property name="dataSource" ref="dataSource"></property>
</bean>
3.整合代码
1.原始DAO开发方式
1.映射文件(User.xml)
2.DAO接口代码以及DAO的实现类代码
3.在application.xml中配置UserDao的实现类
<bean id="userDao" class="xxx.xx.xxx.UserDaoImpl">
//依赖注入SqlSessionFactory
<property name="sqlSessionFactory" ref="sqlSessionFactory"></proerty>
</bean>
4.编写测试代码
2.mapper代理的方式
1.映射文件(UserMapper.xml)
2.Mapper接口
3.配置mapper代理类
1.单个mapper代理类的配置
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
//设置代理类接口
<property name="mapperInterface" value="com.xx.xxx.xx.UserMapper"></property>
//依赖注入SqlSessionFactory
<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean>
2.批量设置mapper代理类
<!--批量配置mapper代理类,默认bean的id为类名首字母小写-->
//通过MapperScannerConfigurer批量扫描创建代理对象
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--配置扫描包-->
<property name="basePackage" value="cn.edu.xidian.c2.mapper" />
<!--只有一个sqlSessionFactory时,默认不需要配置SqlSessionFactory,单独配置也可以-->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
</bean>
2.2 具体整合步骤2:
1.Maven引入需要的jar包(添加依赖 基本的依赖)
2.Spring与Mybatis的整合
1.建立JDBC属性文件(jdbc.properties 文件编码改为utf-8)
2.建立spring-mybatis.xml配置文件(用来完成spring和mybatis整合 主要是:自动扫描、自动注入、配置数据库)
3.Log4j的配置
配置LOG4j的目的是为了更方便测试,使用日志来输出信息,然后所有的项目基本上都是这样一个基本的配置
1.建立log4j.properties配置文件
4.JUnit测试
1.创建测试用表
2.利用MyBatis Generator自动创建代码 这个根据表自动创建实体类、mybatis映射文件、DAO接口
使用MyBatis Generator自动创建代码
3.建立Service接口和实现类
4.建立测试类
5.整合SpringMVC(springmvc的配置文件单独放,然后在web.xml文件中配置整合)
1.配置springmvc.xml(主要是自动扫描控制器、视图模式、注解启动这三个的配置)
2.配置web.xml文件 这里对spring-mybatis.xml配置文件的引入以及配置springmvc的servlet
Mybatis的逆向工程
概念:Mybatis提供来一个逆向工程工具,通过逆向工程,可以帮助程序员根据数据表单表来生成po类、mapper映射文件、mapper接口。
就是通过数据库中的单表自动生成Java代码。
具体笔记见mybatis教案
1.逆向工程使用步骤:
1.创建generator配置文件
generator.xml文件内容可以从逆向工程的jar包下的docs目录下的index.html文件中找到相关的源代码
2.使用java类来执行逆向工程
public class Generator {
public static void main(String[] args) throws Exception{
List<String> warnings = new ArrayList<String>();
boolean overwrite = true;
File configFile = new File("config/generator.xml");
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(configFile);
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config,
callback, warnings);
myBatisGenerator.generate(null);
}
}
3.把生成的代码拷贝到项目中
如果正式项目中已经有po类所在的包了,那么就只需要拷贝po类到指定包下就可以。如果正式项目中没有po包,那么就把逆向工程中整个po类的包拷贝过去。
Mapper.xml和mapper.java的拷贝与po类一样
4.在正式项目中使用逆向工程生成的代码
public class ItemsMapperTest {
// spring上下文
private ApplicationContext ctx;
@Before
public void setUp() throws Exception {
// 读取spring的上下文,然后封装到ctx
ctx = new ClassPathXmlApplicationContext(
"spring/applicationContext.xml");
}
@Test
public void testSelectByExample() {
ItemsMapper mapper = (ItemsMapper) ctx.getBean("itemsMapper");
ItemsExample example = new ItemsExample();
//使用它进行参数封装传递
Criteria criteria = example.createCriteria();
//设置参数
criteria.andNameEqualTo("背包");
List<Items> list = mapper.selectByExample(example);
System.out.println(list);
}
}
注意:
1.mapper.xml文件已经存在时,如果进行重新生成mapper.xml文件,内容不会被覆盖,而是进行mapper.xml文件内容的追加,结果会导致mybatis解析失败
解决方法:删除原来已经生成的mapper.xml文件再进行生成
2.mybatis自动生成的po以及mapper.java文件不是追加而是直接覆盖,所以不会出现此问题。
Mybatis 的查询缓存
1.mybatis缓存分析
mybatis提供查询缓存,如果缓存中有数据就不用从数据库中获取,用于减轻数据压力,提高系统性能。
一级缓存:SqlSession级别的缓存,在操作数据库时需要构造sqlSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据,不同的sqlSession之间的缓存数据区域(HashMap)互相不影响。
二级缓存:mapper级别的缓存,多个SqlSession去操作同一个mapper的sql语句,多个sqlSession可以共用二级缓存,二级缓存是跨SqlSession的。
注意:mybatis默认支持一级缓存
应用:在开发项目过程中,将mybatis与spring进行整合开发,事务控制在service中,一个service方法中包括很多mapper方法调用。
注意:mybatis默认没有开启二级缓存
2.mybatis 开启二级缓存
1.在核心配置文件SqlMapConfig.xml中添加开启二级缓存总开关
<setting name="cacheEnable" value="true"/>
2.在UserMapper映射文件中开启二级缓存(开启mapper下的namespace的二级缓存,默认使用mybatis提供的PerpetualCache)
<cache></cache>
3.实现序列化(因为二级缓存的数据不一定都是存储在内存中的,所以需要给缓存的对象执行序列化,如果该类存在父类,也需要给父类实现序列化)
3.mybatis 禁用二级缓存
在statement中设置userCache=false禁用当前select语句的二级缓存,每次查询都要去数据库中查询,默认情况下是true,该statement使用二级缓存。
<select id="findUserById" parameterType="int" resultType="cn.itcast.mybatis.po.User" useCache="true">
SELECT * FROM user WHERE id = #{id}
</select>
4.mybatis刷新二级缓存
见mybatis教案
5.mybatis 延迟加载
见mybatis教案
SSM整合
1.Spring MVC
作用于WEB层,相当于Controller,用来处理用户请求。例:用户在地址栏输入http://网站域名/login,那么springmvc就会拦截到这个请求,并且调用controller层中相应的方法(虽然中间可能会包含很多业务,但是这些都不是SpringMVC来处理)
最终将结果返回给用户,并且返回相应的页面(可以只返回json/xml等格式数据)
总结:SpringMVC只负责跟用户打交道,做前面和后面的活,中间的实现过程等业务不是它负责。
2.Spring
最常见,经常用到的是IOC容器,其可以装载bean(Java中的类,也包括service dao里面的)有了这个机制,我们就不用在每次使用这个类的时候为它初始化,很少看到关键字new。另外spring的aop,事务管理等等都是我们经常用到的。
3.mybatis
1.能够自由控制SQL
2.可以使用xml的方式来组织管理我们的SQL
1.SSM整合
1.Java各种对象的区分
PO 持久对象(entity) PO每个属性基本上都对应数据库表里面的某个字段,完全是一个符合Java Bean规范的Java对象,没有增强别的属性和方法。持久对象是由<insert></insert>数据库创建,由数据库<delete></delete>删除的。基本上持久对象生命周期和数据库密切相关。
VO 值对象 通常用于业务层(Service层)之间的数据传输,与PO一样只包含数据,此外应该抽象出业务对象。表现层对象(View Object),主要对应展示界面显示的数据对象,用一个VO对象来封装整个界面展示所需要的对象数据。
DTO 数据传输对象 是一种设计模式之间传输数据的软件应用系统 作用仅在应用程序的各个子系统间传输数据,在表现层展示。与POJO对应一个数据库实体不同,DTO不对应一个实体,可能仅存储实体的部分属性或加入符合传输需求的其他的属性。
POJO 简单的Java对象 实际上可以理解POJO为简单的实体类 方便开发者使用数据库中的数据表
DTO 数据传输对象(起到数据封装与隔离的作用)
在实际的项目中,DTO分为两层传输
1.Service层向Controller层,这一层的DTO封装Service执行结果给Controller简化业务数据,只提取部分业务相关字段或补充处理相关字段,不同业务可能有不同的此类dto,具有业务相关性。
2.Controller层向WEB前端,这一层DTO封装Controller执行结果,返回前端WEB,请求返回实体封装类,适用于所有ajax请求返回的类型实体,无业务相关性。
SSM整合知识点概括
1.Controller方法返回值(指定返回到哪个页面,指定返回到页面的数据)
1)ModelAndView
modelAndView.addObject("itemList", list); 指定返回页面的数据
modelAndView.setViewName("itemList"); 指定返回的页面
2)String(推荐使用)
返回普通字符串,就是页面去掉扩展名的名称, 返回给页面数据通过Model来完成
返回的字符串以forward:开头为请求转发
返回的字符串以redirect:开头为重定向
3)返回void(使用它破坏了springMvc的结构,所以不建议使用)
可以使用request.setAttribut(因为我们写的是服务端,所以使用request对象向view中传输数据) 来给页面返回数据
可以使用request.getRquestDispatcher().forward()来指定返回的页面
如果controller返回值为void则不走springMvc的组件,所以要写页面的完整路径名称
相对路径:相对于当前目录,也就是在当前类的目录下,这时候可以使用相对路径跳转
绝对路径:从项目名后开始.
注意:在springMvc中不管是forward还是redirect后面凡是以/开头的为绝对路径,不以/开头的为相对路径。
例如:
forward:/items/itemEdit.action 为绝对路径
forward:itemEdit.action为相对路径
2.架构级别异常处理
此异常编写是实现全局异常处理器接口,目的主要为了防止项目上线后给用户抛500等异常信息,所以需要在架构级别上整体处理.hold住异常
1.首先自定义全局异常处理器实现HandlerExceptionResolver接口
public class GlobalHandleExceptionResolver implements HandlerExceptionResolver {//....
2.在spirngMvc.xml中配置生效
3.上传图片
1)在tomcat中配置虚拟图片服务器
2)导入fileupload的jar包
3)在springMvc.xml中配置上传组件
4)在页面上编写上传域,更改form标签的类型
5)在controller方法中可以使用MultiPartFile接口接收上传的图片
6)将文件名保存到数据库,将图片保存到磁盘中
4.JSON数据交互
1.首先在pom.xml中配置好需要的jar包(jackson的jar包)
2.@Requestbody:将页面传到controller中的json格式字符串自动转换成java的pojo对象
@ResponseBody:将java中pojo对象自动转换成json格式字符串返回给页面
5.RestFul风格支持
此风格就是对URL的命名标准,此标准要求URL中只能有名词,要求URL中不能用?传参
传参数:
页面:${pageContext.request.contextPath}/items/itemEdit/${item.id}
方法:@RequestMapping("/itemEdit/{id}")
方法:@PathVariable("id") Integer id
6.拦截器
作用:拦截请求,一般在登录的时候用得比较多
1.需要编写自定义拦截器类,实现HandlerInterceptor接口
public class AuthorizedInterceptor implements HandlerInterceptor {//......
2.在spirngMvc.xml中配置拦截器生效
7.登录权限验证
1)编写登录的Controller,编写跳转到登录页面,编写登录验证方法
2)编写登录页面
3)编写拦截器
总结:随意访问一个页面,拦截器会拦截请求,会验证session是否有登录信息。如果已经登录,放。如果未登录,跳转到登录页面
在登录页面输入用户名、密码,点击登录按钮,拦截器会拦截请求,如果登录路径在Controller方法中判断用户名和密码正确则将登录信息方法session中。