编程语言JavaScript是ECMAScript的实现和扩展 。ECMAScript是由ECMA(一个类似W3C的标准组织)参与进行标准化的语法规范。ECMAScript定义了:
[语言语法] – 语法解析规则、关键字、语句、声明、运算符等。
[类型]– 布尔型、数字、字符串、对象等。
[原型和继承]
内建对象和函数的
[标准库] – [JSON]、[Math]、[数组方法]、[对象自省方法]等。
2009年发布的改进版本ES5,引入了[Object.create()]、[Object.defineProperty()]、[getters]和[setters]、[严格模式]以及[JSON]对象。
ECMAScript 6.0(以下简称ES6)是JavaScript语言的下一代标准,2015年6月正式发布。它的目标,是使得JavaScript语言可以用来编写复杂的大型应用程序,成为企业级开发语言。
我们都是知道在ES6以前,var关键字声明变量。无论声明在何处,都会被视为声明在函数的最顶部(不在函数内即在全局作用域的最顶部)。这就是函数变量提升例如
function aa(flag) {
if (flag) {
var test = 'hello man'
}
console.log(test)
}
aa(true);
以上的代码实际上是:
function aa(flag) {
var test // 变量提升
if(flag) {
test = 'hello man'
}
console.log(test)
}
aa(true);
所以不用关心bool是否为true or false。实际上,无论如何test都会被创建声明。
ES6声明变量特性:
通常用let和const来声明,let表示变量、const表示常量。let和const都是块级作用域。怎么理解这个块级作用域?在一个函数内部 ,在一个代码块内部。
看以下代码
function aa(flag) {
if (flag) {
let test = 'hello man'
}
console.log(test)
}
aa(true);
const 用于声明常量,看以下代码
const name = '张飞'
name = '赵云' //再次赋值此时会报错
es6模板字符简直是开发者的福音,解决了ES5在字符串功能上的痛点。
第一个用途,基本的字符串格式化。将表达式嵌入字符串中进行拼接。用${}来界定。
//es5
var name = '张飞'
console.log('hello' + name)
//es6
const name2 = '赵云'
console.log(`hello ${name2}`) //hello 赵云
第二个用途,在ES5时我们通过反斜杠()来做多行字符串或者字符串一行行拼接。ES6反引号(``)直接搞定。
// es5
var msg = "Hi \
man!"
// es6
const template = `
hello world
`
ES6很有意思的一部分就是函数的快捷写法。也就是箭头函数。
箭头函数最直观的三个特点。
1不需要function关键字来创建函数
2省略return关键字
3继承当前上下文的 this 关键字
//ES5用法
function add(a,b){
return a+b;
}
console.log(add(100,200));
//ES6用法
add2 = (a,b) => {
return a+b;
}
console.log(add2(100,200));
//省略return关键字
add3 = (a,b) => a+b;
console.log(add3(100,200));
通用 Mapper4 是一个可以实现任意 MyBatis 通用方法的框架,项目提供了常规的增删改查操作以及Example
相关的单表操作。通用 Mapper 是为了解决 MyBatis 使用中 90% 的基本操作,使用它可以很方便的进行开发,可以节省开发人员大量的时间
Spring 集成
这是 MyBatis 最常用的一种的环境。通用 Mapper 提供了多种方式来和 Spring 进行集成。
在开始配置前,先添加相关的依赖。
正常情况下,Spring 和 MyBatis 的集成环境中,应该已经存在下面的依赖:
org.mybatis
mybatis
版本号
org.mybatis
mybatis-spring
版本号
org.springframework
spring-context
版本号
org.springframework
spring-tx
版本号
org.springframework
spring-jdbc
版本号
相关依赖和版本可以通过 http://mvnrepository.com/ 进行搜索
通用 Mapper 支持 MyBatis 3.2.4+
集成通用 Mapper 在上面的基础上添加下面的依赖:
tk.mybatis
mapper
最新版本
通用 Mapper 最新版本看这里:http://mvnrepository.com/artifact/tk.mybatis/mapper
tk.mybatis:mapper 依赖包含了通用 Mapper 的基础代码以及和 Spring 集成必须的代码
和 Spring 进行集成时,分为 XML 和注解配置两种方式,每种方式又有不同的配置方式。
这里提供了很多配置方式,使用时选择一种改动最小的方式即可!
使用 MapperScannerConfigurer
和通用 Mapper 以前版本一样,可以直接使用 tk.mybatis 提供的 tk.mybatis.spring.mapper.MapperScannerConfigurer
进行配置,这个配置和 MyBatis 官方提供的 org.mybatis.spring.mapper.MapperScannerConfigurer
区别只是第一层的包名,tk
和 org
。所以使用这种方式时,如果你项目已经使用 org.
进行了配置,只需要改成 tk.
即可。
@MapperScan
注解使用 Configuration 进行配置
这里使用 MyBatis 官方的 @MapperScan
注解。
@Configuration
@MapperScan(basepackages="cn.nyse.dao"
)
public class MyBatisConfigProperties {
@Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
//tk.mybatis.mapper.session.Configuration
Configuration configuration = new Configuration();
//可以对 MapperHelper 进行配置后 set
//configuration.setMapperHelper(new MapperHelper());
//解决查询返回Map时设置值为null的字段没有在结果集中
configuration.setCallSettersOnNulls(true);
//设置为 tk 提供的 Configuration
sessionFactory.setConfiguration(configuration);
return sessionFactory.getObject();
}
}
示例针对 MySql 数据库(数据库对主键影响较大,和 insert 关系密切)。
数据库有如下表:
CREATE TABLE `country` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`countryname` varchar(255) DEFAULT NULL COMMENT '名称',
`countrycode` varchar(255) DEFAULT NULL COMMENT '代码',
PRIMARY KEY (`Id`)
) ENGINE=InnoDB AUTO_INCREMENT=10011 DEFAULT CHARSET=utf8 COMMENT='国家信息';
对应的 Java 实体类型如下:
public class Country {
@Id
private Integer id;
private String countryname;
private String countrycode;
//省略 getter 和 setter
}
最简单的情况下,只需要一个 @Id
标记字段为主键即可。数据库中的字段名和实体类的字段名是完全相同的,这中情况下实体和表可以直接映射。
提醒:如果实体类中没有一个标记 @Id 的字段,当你使用带有 ByPrimaryKey 的方法时,所有的字段会作为联合主键来使用,也就会出现类似 where id = ? and countryname = ? and countrycode = ?的情况。
第四章会介绍代码生成器,可以自动生成上面的实体和下面的接口代码
通用 Mapper 提供了大量的通用接口,这里以最常用的 Mapper 接口为例
该实体类对应的数据库操作接口如下:
import tk.mybatis.mapper.common.Mapper;
public interface CountryMapper extends Mapper {
}
只要配置 MyBatis 时能注册或者扫描到该接口,该接口提供的方法就都可以使用。
该接口默认继承的方法如下:
从 MyBatis 中获取该接口后就可以直接使用:
//从 MyBatis 或者 Spring 中获取 countryMapper,然后调用 selectAll 方法
List countries = countryMapper.selectAll();
//根据主键查询
Country country = countryMapper.selectByPrimaryKey(1);
//或者使用对象传参,适用于1个字段或者多个字段联合主键使用
Country query = new Country();
query.setId(1);
country = countryMapper.selectByPrimaryKey(query);
如果想要增加自己写的方法,可以直接在 CountryMapper 中增加。
使用纯接口注解方式时
import org.apache.ibatis.annotations.Select;
import tk.mybatis.mapper.common.Mapper;
public interface CountryMapper extends Mapper {
@Select("select * from country where countryname = #{countryname}")
Country selectByCountryName(String countryname);
}
这里只是举了个简单的例子,可以是很复杂的查询。
如果使用 XML 方式,需要提供接口对应的 XML 文件
例如提供了 CountryMapper.xml
文件,内容如下:
在接口中添加对应的方法:
import tk.mybatis.mapper.common.Mapper;
public interface CountryMapper extends Mapper {
Country selectByCountryName(String countryname);
}
在接口中添加其他方法的时候和只用 MyBatis 是完全一样的,但是需要注意,在对应的 XML 中,不能出现和继承接口中同名的方法!
通用 Mapper 中,默认情况下是将实体类字段按照驼峰转下划线形式的表名列名进行转换。
例如
实体类的
userName
可以映射到表的user_name
上。
@Table
注解可以配置 name
,catalog
和 schema
三个属性,配置 name
属性后,直接使用提供的表名,不再根据实体类名进行转换。其他两个属性中,同时配置时,catalog
优先级高于 schema
,也就是只有 catalog
会生效。
配置示例如下:
@Table(name = "sys_user")
public class User
@Column
注解@Column
注解支持 name
, insertable
和 updateable
三个属性。
name
配置映射的列名。
insertable
对提供的 insert
方法有效,如果设置 false
就不会出现在 SQL 中。
updateable
对提供的 update
方法有效,设置为 false
后不会出现在 SQL 中。
配置示例如:
@Column(name = "user_name")
private String name;
除了直接映射 name
到 user_name
这种用法外,在使用关键字的情况,还会有下面的用法:
@Column(name = "`order`")
private String order;
对于关键字这种情况,通用 Mapper 支持自动转换
@Transient
注解一般情况下,实体中的字段和数据库表中的字段是一一对应的,但是也有很多情况我们会在实体中增加一些额外的属性,这种情况下,就需要使用 @Transient
注解来告诉通用 Mapper 这不是表中的字段。
默认情况下,只有简单类型会被自动认为是表中的字段(可以通过配置中的 useSimpleType 控制)。
这里的简单类型不包含 Java 中的8种基本类型:
byte,short,int,long,float,double,char,boolean
这是因为在类中,基本类型会有默认值,而 MyBatis 中经常会需要判断属性值是否为空,所以不要在类中使用基本类型,否则会遇到莫名其妙的错误。
对于类中的复杂对象,以及 Map
,List
等属性不需要配置这个注解。
配置示例:
@Transient
private String otherThings; //非数据库表中字段
主键策略和数据库关系很大,有些数据库支持主键自增,而有些数据库只能通过序列来获得。
getGeneratedKeys
方法取回主键的情况这种情况首先需要数据库支持自增,其次数据库提供的 JDBC 支持 getGeneratedKeys
方法。
常见的如 MySql,SqlServer 支持这种模式。
这种情况下,配置主键策略最简单。
用法如下:
@Id
@KeySql(useGeneratedKeys = true)
private Long id;
为了让大家容易理解这里配置和 MyBatis 写法的关系,大家可以看看对应生成的 XML 代码:
insert into country (id, countryname, countrycode)
values (#{id},#{countryname},#{countrycode})
使用该插件可以很方便的生成实体类、Mapper接口以及对应的XML文件。
通用 Mapper 专用代码生成器生成的 Model 会在原有基础上增加 @Table,@Id,@Column
等注解,方便自动会数据库字段进行映射。
maven-compiler-plugin
${jdk.version}
org.mybatis.generator
mybatis-generator-maven-plugin
1.3.6
${basedir}/src/main/resources/generator/generatorConfig.xml
true
true
mysql
mysql-connector-java
5.1.35
tk.mybatis
mapper
4.1.5
在插件中配置了配置文件的路径,覆盖和输出详细日志三个参数。
除此之外需要特别注意的是
,MBG 配置中用到的所有外部代码都必须通过依赖方式配置在这里,否则运行时会提示找不到对应的类而报错。这里有两个必须的依赖,一个是 JDBC 驱动,另一个是 Mapper 的插件。
配置文件generatorConfig.xml:
这里和之前相差不多,只是通过
引入了外部属性文件,在
配置时,使用的属性文件中的参数。
通用 Mapper 中的 Example 方法有两大类定义,一个参数和两个参数的,例如下面两个:
List selectByExample(Object example);
int updateByExampleSelective(@Param("record") T record, @Param("example") Object example);
所有 Example 方法中的 example 类型都是 Object
类型,这是因为通用 Mapper 支持所有符合 Example 结构的参数,例如通过 MBG 生成的 CountryExample、UserExample 类。还有通用 Mapper 中提供的通用 Example,以及支持 Java8 方法引用的 Weekend 类型。
配置中有一个和 Example 有关的参数,点击查看 3.14 checkExampleEntityClass。
用法如下:
CountryExample example = new CountryExample();
example.createCriteria().andCountrynameLike("A%");
example.or().andIdGreaterThan(100);
example.setDistinct(true);
int count = mapper.deleteByExample(example);
对于的 SQL 日志如下:
DEBUG [main] - ==> Preparing: DELETE FROM country WHERE ( countryname like ? ) or ( Id > ? )
DEBUG [main] - ==> Parameters: A%(String), 100(Integer)
DEBUG [main] - <== Updates: 95
生成的 CountryExample 中包含了和字段相关的多种方法,根据自己的需要设置相应的条件即可。
这是由通用 Mapper 提供的一个类,这个类和 MBG 生成的相比,需要自己设置属性名。这个类还额外提供了更多的方法。
示例:
Example example = new Example(Country.class);
example.setForUpdate(true);
example.createCriteria().andGreaterThan("id", 100).andLessThan("id",151);
example.or().andLessThan("id", 41);
List countries = mapper.selectByExample(example);
日志:
DEBUG [main] - ==> Preparing: SELECT id,countryname,countrycode FROM country WHERE ( id > ? and id < ? ) or ( id < ? ) ORDER BY id desc FOR UPDATE
DEBUG [main] - ==> Parameters: 100(Integer), 151(Integer), 41(Integer)
DEBUG [main] - <== Total: 90
示例:
Example example = new Example(Country.class);
Example.Criteria criteria = example.createCriteria();
if(query.getCountryname() != null){
criteria.andLike("countryname", query.getCountryname() + "%");
}
if(query.getId() != null){
criteria.andGreaterThan("id", query.getId());
}
List countries = mapper.selectByExample(example);
日志:
DEBUG [main] - ==> Preparing: SELECT id,countryname,countrycode FROM country WHERE ( countryname like ? ) ORDER BY id desc
DEBUG [main] - ==> Parameters: China%(String)
DEBUG [main] - <== Total: 1
示例:
Example example = new Example(Country.class);
example.orderBy("id").desc().orderBy("countryname").orderBy("countrycode").asc();
List countries = mapper.selectByExample(example);
日志:
DEBUG [main] - ==> Preparing: SELECT id,countryname,countrycode FROM country order by id DESC,countryname,countrycode ASC
DEBUG [main] - ==> Parameters:
DEBUG [main] - <== Total: 183
示例:
CountryExample example = new CountryExample();
//设置 distinct
example.setDistinct(true);
example.createCriteria().andCountrynameLike("A%");
example.or().andIdGreaterThan(100);
List countries = mapper.selectByExample(example);
日志:
DEBUG [main] - ==> Preparing: SELECT distinct id,countryname,countrycode FROM country WHERE ( countryname like ? ) or ( Id > ? ) ORDER BY id desc
DEBUG [main] - ==> Parameters: A%(String), 100(Integer)
DEBUG [main] - <== Total: 95
示例:
Example example = new Example(Country.class);
example.selectProperties("id", "countryname");
List countries = mapper.selectByExample(example);
日志:
DEBUG [main] - ==> Preparing: SELECT id , countryname FROM country ORDER BY id desc
DEBUG [main] - ==> Parameters:
DEBUG [main] - <== Total: 183
除了这里提到的方法外,还有很多其他的方法,可以查看 Example 源码进行了解。
示例:
Example example = Example.builder(Country.class)
.select("countryname")
.where(Sqls.custom().andGreaterThan("id", 100))
.orderByAsc("countrycode")
.forUpdate()
.build();
List countries = mapper.selectByExample(example);
日志:
DEBUG [main] - ==> Preparing: SELECT countryname FROM country WHERE ( id > ? ) order by countrycode Asc FOR UPDATE
DEBUG [main] - ==> Parameters: 100(Integer)
DEBUG [main] - <== Total: 83
官方参考文档:
https://github.com/abel533/Mapper
package cn.nyse.test.service;
import cn.nyse.entity.User;
import org.apache.ibatis.session.RowBounds;
import java.util.List;
public interface IService {
int deleteByPrimaryKey(Object o);
int delete(T t);
int insert(T t);
int insertSelective(T t);
boolean existsWithPrimaryKey(Object o);
List selectAll();
User selectByPrimaryKey(Object o);
int selectCount(T t);
List select(T t);
User selectOne(T t);
int updateByPrimaryKey(T t);
int updateByPrimaryKeySelective(T t);
int deleteByExample(Object o);
List selectByExample(Object o);
int selectCountByExample(Object o);
User selectOneByExample(Object o);
int updateByExample(T t, Object o);
int updateByExampleSelective(T t, Object o);
List selectByExampleAndRowBounds(Object o, RowBounds rowBounds);
List selectByRowBounds(T t, RowBounds rowBounds);
}
package cn.nyse.test.service.impl;
import cn.nyse.test.service.IService;
import org.apache.ibatis.session.RowBounds;
import org.springframework.beans.factory.annotation.Autowired;
import tk.mybatis.mapper.common.Mapper;
import java.util.List;
public class ServiceImpl implements IService {
@Autowired
Mapper mapper;
@Override
public int deleteByPrimaryKey(Object o) {
return mapper.deleteByPrimaryKey(o);
}
@Override
public int delete(T t) {
return mapper.delete(t);
}
@Override
public int insert(T t) {
return mapper.insert(t);
}
@Override
public int insertSelective(T t) {
return mapper.insertSelective(t);
}
@Override
public boolean existsWithPrimaryKey(Object o) {
return mapper.existsWithPrimaryKey(o);
}
@Override
public List selectAll() {
return mapper.selectAll();
}
@Override
public T selectByPrimaryKey(Object o) {
return mapper.selectByPrimaryKey(o);
}
@Override
public int selectCount(T t) {
return mapper.selectCount(t);
}
@Override
public List select(T t) {
return mapper.select(t);
}
@Override
public T selectOne(T t) {
return mapper.selectOne(t);
}
@Override
public int updateByPrimaryKey(T t) {
return mapper.updateByPrimaryKey(t);
}
@Override
public int updateByPrimaryKeySelective(T t) {
return mapper.updateByPrimaryKeySelective(t);
}
@Override
public int deleteByExample(Object o) {
return mapper.deleteByExample(o);
}
@Override
public List selectByExample(Object o) {
return mapper.selectByExample(o);
}
@Override
public int selectCountByExample(Object o) {
return mapper.selectCountByExample(o);
}
@Override
public T selectOneByExample(Object o) {
return mapper.selectOneByExample(o);
}
@Override
public int updateByExample(T t, Object o) {
return mapper.updateByExample(t,o);
}
@Override
public int updateByExampleSelective(T t, Object o) {
return mapper.updateByExampleSelective(t,o);
}
@Override
public List selectByExampleAndRowBounds(Object o, RowBounds rowBounds) {
return mapper.selectByExampleAndRowBounds(o,rowBounds);
}
@Override
public List selectByRowBounds(T t, RowBounds rowBounds) {
return mapper.selectByRowBounds(t,rowBounds);
}
}
1.依赖包导入
com.github.pagehelper
pagehelper
3.7.5
com.github.jsqlparser
jsqlparser
0.9.1
2.修改mybatis配置文件
@Bean
public SqlSessionFactoryBean getFactoryBean(DruidDataSource dataSource){
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
//1.配置数据源
factoryBean.setDataSource(dataSource);
//2.配置别名
factoryBean.setTypeAliasesPackage("cn.nyse.entity");
PageInterceptor interceptor = new PageInterceptor();
Properties properties = new Properties();
interceptor.setProperties(properties);
Interceptor[] interceptors = new Interceptor[]{interceptor};
factoryBean.setPlugins(interceptors);//设置使用第三方插件
//创建TKmapper配置对象 默认开启驼峰命名匹配
tk.mybatis.mapper.session.Configuration configuration = new tk.mybatis.mapper.session.Configuration();
//解决查询返回Map时设置值为null的字段没有在结果集中configuration.setCallSettersOnNulls(true);
configuration.setMapUnderscoreToCamelCase(true);//开启支持驼峰命名
factoryBean.setConfiguration(configuration);
return factoryBean;
}
在需要分页查询的mapper方法调用前使用,紧跟在这个方法后的第一个MyBatis 查询方法会被进行分页。
PageHelper.startPage(1, 10);
//Mapper接口方式的调用,推荐这种使用方式。
PageHelper.startPage(1, 10);
List list = countryMapper.selectIf(1);
//用PageInfo对结果进行包装
PageInfo page = new PageInfo(list);
//测试PageInfo全部属性
//PageInfo包含了非常全面的分页属性
assertEquals(1, page.getPageNum());
assertEquals(10, page.getPageSize());
assertEquals(1, page.getStartRow());
assertEquals(10, page.getEndRow());
assertEquals(183, page.getTotal());
assertEquals(19, page.getPages());
assertEquals(1, page.getFirstPage());
assertEquals(8, page.getLastPage());
assertEquals(true, page.isFirstPage());
assertEquals(false, page.isLastPage());
assertEquals(false, page.isHasPreviousPage());
assertEquals(true, page.isHasNextPage());
new tk.mybatis.mapper.session.Configuration();
//解决查询返回Map时设置值为null的字段没有在结果集中configuration.setCallSettersOnNulls(true);
configuration.setMapUnderscoreToCamelCase(true);//开启支持驼峰命名
factoryBean.setConfiguration(configuration);
return factoryBean;
}
在需要分页查询的mapper方法调用前使用,紧跟在这个方法后的第一个MyBatis 查询方法会被进行分页。
PageHelper.startPage(1, 10);
//Mapper接口方式的调用,推荐这种使用方式。
PageHelper.startPage(1, 10);
List list = countryMapper.selectIf(1);
//用PageInfo对结果进行包装
PageInfo page = new PageInfo(list);
//测试PageInfo全部属性
//PageInfo包含了非常全面的分页属性
assertEquals(1, page.getPageNum());
assertEquals(10, page.getPageSize());
assertEquals(1, page.getStartRow());
assertEquals(10, page.getEndRow());
assertEquals(183, page.getTotal());
assertEquals(19, page.getPages());
assertEquals(1, page.getFirstPage());
assertEquals(8, page.getLastPage());
assertEquals(true, page.isFirstPage());
assertEquals(false, page.isLastPage());
assertEquals(false, page.isHasPreviousPage());
assertEquals(true, page.isHasNextPage());