MyBatis学习总结大全:
- MyBatis学习总结第一天
- MyBatis学习总结第二天
- MyBatis学习总结第三天
今日大纲
- MyBatis的CRUD
- Mybatis的传值
- Mybatis的其他标签使用
1.Mybatis的CRUD
1.1、UPDATE
<!-- 修改数据
使用update语句,id:必要属性,随便写,但要保证在改xml文件是唯一
没有返回值:因为更新语句,它的返回值是影响的行数,所以不需要设置resultType
-->
<update id="updateUser" >
update t_user set pwd=#{pwd} where id=#{id}
</update>
实现:
/**
*
* @Description:有参数的数据传递
* @author
* @throws IOException
* @date 2017年10月27日
*/
@Test
public void updateUser1() throws IOException{
Reader re = Resources.getResourceAsReader("mybatis.cfg.xml");
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(re);
SqlSession openSession = build.openSession();
/**
* 第一个参数: statement id
* 第二个参数:要传递的参数对象
*
*
*/
// User user = new User();
// user.setPwd("jkl");
// user.setId(1001);
Map<String, Object> user= new HashMap<>();
user.put("pwd", "zxc");
user.put("id", 1001);
int update = openSession.update("updateUser", user);
openSession.commit();
System.out.println(update);
openSession.close();
}
删除语句
<!-- 删除一个用户 -->
<delete id="deleteUserById">
delete from t_user where id= #{id}
</delete>
实现:
/**
*
* @Description: 删除
* @throws IOException
* @author mao
* @date 2017年10月27日
*/
@Test
public void deleteUsesr() throws IOException{
Reader re = Resources.getResourceAsReader("mybatis.cfg.xml");
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(re);
SqlSession openSession = build.openSession();
/**
* 参数传递:
* 1.对象类型
* 2.map集合类型
* 3.简单类型
*/
// User user = new User();
// user.setId(1004);
// Map<String, Object> user = new HashMap<>();
// user.put("id", 1005);
/**
* delete():
* 第一个参数:statement id
* 第二参数: statement需要的参数
* 返回值是影响的行数
*/
int delete = openSession.delete("deleteUserById", 1006);
System.out.println(delete);
openSession.commit();
openSession.close();
}
添加
MYSQL的新增,通过主键自增
<!-- 主键自增的添加用户
使用mysql的主键自增,不需要添加主键,在往数据库添加数据的时候,mysql会自动生成主键
useGeneratedKeys="true":
表示的如果访问的数据,有主键自增,就执行主键自增,没有就不执行,默认是开启的
true:开启主键自增
false:关闭主键自增
-->
<insert id="saveUser1">
<!-- selectKey用于拿到主键信息
keyColumn:对应的数据库表主键信息.
例如:用户表:主键是id ==》keyColumn="id"
书籍表:主键是book_id ==> keyColumn="book_id"
keyProperty:数据表对应的对象中表示主键的属性
例如:用户表:主键是id ==》对象是主键属性是id==》keyProperty="id"
书籍表:主键是book_id ==> 对象是主键属性是bookId==》keyProperty="bookId"
resultType:返回值类型,需要写成对象的全路径
order:
BEFORE:是在insert语句执行之前,获取主键值
AFTER:是在insert语句执行之后,获取主键值
SELECT @@identity as id :是mysql获取主键的方式,是将主键信息赋值给对象属性
@@identity它与主键信息对应不上,所以 给它一个别名,as id:id对应的属性
获取主键值=》主键字段=》对象的属性
-->
<selectKey keyColumn="id" keyProperty="id"
resultType="java.lang.Integer" order="AFTER">
SELECT @@identity as id
</selectKey>
insert into t_user(name,pwd,age)
values(#{name},#{pwd},#{age})
</insert>
Oracle的新增,通过序列新增
<!--
oracle 新增
oracle 是通过序列进行主键生成的,
oracle新增需要写主键值
-->
<insert id="saveUser2" >
<!--
test.currval :序列当前值
test.nextVal:序列下一个值
order="AFTER":在insert之后获取值,
使用test.currval来获取,在insert语句中是test.nextVal来添加值
order="BEFORE":在insert之前获取值
使用test.nextVal来获取,在insert语句中是test.currval来添加值
-->
<selectKey keyColumn="id" keyProperty="id" resultType="java.lang.Integer"
order="AFTER">
select test.currval from dual
</selectKey>
insert into t_user(id,name,pwd,age)
values(test.nextVal,#{name},#{pwd},#{age})
</insert>
查询
<!-- 查询所有数据 -->
<select id="getUsers" resultType="user">
select * from t_user
</select>
<!-- 根据id进行查询 -->
<select id="getUserById" resultType="user">
select * from t_user where id= #{id}
</select>
<!-- 返回map集合查询 -->
<select id="getUserForMap" resultType="user">
select * from t_user where id=#{id}
</select>
<!-- 模糊查询 -->
<select id="getUserByName" resultType="user">
select * from t_user where name like #{name}
</select>
<!-- 模糊查询的第二种方式 oracle-->
<select id="getUserByName1" resultType="user">
select * from t_user where name like '%'||#{name}||'%'
</select>
<!-- 模糊查询的第二种方式 mysql
concat:mysql是字符串拼接
concat(参数无数个):参数是可以无数个,以,分割,mysql将这个字符进行自动拼接
-->
<select id="getUserByName2" resultType="User">
select * from t_user where name like concat('%',#{name},'%')
</select>
<!-- 分页查询
mysql:分页使用函数limit,两个参数与mybatis需要提供的两个参数是一样的
-->
<select id="getUserForPage" resultType="user">
select * from t_user limit #{page},#{size}
</select>
实现:
/**
*
* @ClassName:TestSelect
* @Description:查询
* @Company: 北京尚学堂科技有限公司 www.bjsxt.com
* @author mao
* @date 2017年10月27日
*/
public class TestSelect {
/**
* @Before|@After它俩是junit的注解
* @Before:在执行@Test注解方法之前执行
*
* @After:在执行@Test注解方法之后执行
*/
private SqlSession session;
/**
*
* @Description:获取session
* @author mao
* @date 2017年10月27日
*/
@Before
public void getSession(){
session = MybatisUtil.getSession();
}
/**
*
* @Description:物理分页
* 要多少条数据,就查询多少条数据,不会产生数据冗余,但是它增加数据库访问次数
* 企业中,大部分使用的是物理分页
* @author mao
* @date 2017年10月27日
*/
@Test
public void getUserForPage1(){
int page = 3; //要显示第几页
int size = 3; //每页显示多少条
Map<String, Object> map = new HashMap<>();
map.put("page", (page-1)*size);
map.put("size", size);
List<User> selectList = session.selectList("getUserForPage",map);
for (User user : selectList) {
System.out.println(user);
}
}
/**
*
* @Description: 逻辑分页查询
* 第一种方式:使用mybatis提供的分页查询
* 他逻辑查询,它一次查询出最大下标+1值,它会产生数据冗余,导致内容压力大
* @author mao
* @date 2017年10月27日
*/
@Test
public void getUserByPage(){
/**
* 第一个参数:statement id
* 第二个参数:statement所需要的参数
* 第三个参数:mybatis提供的分页查询类
*/
/**
* RowBounds:mybatis提供的分页查询类,
* offset:数据开始查询的下标
* limit:一次要查询多少条
*/
int page = 3; //要显示第几页
int size = 3; //每页显示多少条
RowBounds rows = new RowBounds((page-1)*size, size);
List<User> selectList = session.selectList("getUsers", null, rows);
for (User user : selectList) {
System.out.println(user);
}
}
/**
*
* @Description:查询所有数据
* @author mao
* @date 2017年10月27日
*/
@Test
public void getUsers(){
List<User> selectList = session.selectList("getUsers");
for (User user : selectList) {
System.out.println(user);
}
}
/**
* 根据主键查询用户
*/
@Test
public void getUserById(){
User selectOne = session.selectOne("getUserById", 2101);
System.out.println(selectOne);
}
/**
*
* @Description:根据主键查询数据,返回为map集合
* @author mao
* @date 2017年10月27日
*/
@Test
public void getUserForMap(){
User user = new User();
user.setId(2101);
/**
* selectMap:
* 第一个参数:statement id
* 第二个参数: statement 需要的参数
* 第三个参数:map 的 key值
*
* key值的类型:与第三个参数的类型一致
* value值的类型:与resultType的值一致
*/
Map<Integer, User> selectMap = session.selectMap("getUserForMap",user, "id" );
System.out.println(selectMap);
}
/**
*
* @Description: 模糊查询
* 如果是手写的%%,不需要自己手写单引号,mybatis的会自动的进行补充
* @author mao
* @date 2017年10月27日
*/
@Test
public void getUserByName(){
/**
* 模糊查询的第一种方式:适合oracle和mysql
*/
// List<User> selectList = session.selectList("getUserByName", "%张%");
// for (User user : selectList) {
// System.out.println(user);
// }
/**
* 模糊查询的第二种方式 oracle
*/
// List<User> selectList2 = session.selectList("getUserByName1", "张");
// for (User user : selectList2) {
// System.out.println(user);
// }
/**
* 模糊查询第二种方式 mysql的
*/
List<User> selectList = session.selectList("getUserByName2", "张");
for (User user : selectList) {
System.out.println(user);
}
}
/**
*
* @Description:关闭session
* @author mao
* @date 2017年10月27日
*/
@After
public void closeSession(){
MybatisUtil.closeSession();
}
}
占位符 #{}
<!-- 修改数据
使用update语句,id:必要属性,随便写,但要保证在改xml文件是唯一
没有返回值:因为更新语句,它的返回值是影响的行数,所以不需要设置resultType
-->
<update id="updateUser" >
update t_user set pwd=#{pwd} where id=#{id}
</update>
参数传递
简单数据类型:
简单类型传递参数一般我们指的是:int\integer\string\long等类型,传递的参数类型要与statement的形参要求的类型一致。
/**
*
* @Description: 删除
* @throws IOException
* @author mao
* @date 2017年10月27日
*/
@Test
public void deleteUsesr() throws IOException{
Reader re = Resources.getResourceAsReader("mybatis.cfg.xml");
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(re);
SqlSession openSession = build.openSession();
/**
* 参数传递:
* 1.对象类型
* 2.map集合类型
* 3.简单类型
*/
// User user = new User();
// user.setId(1004);
// Map<String, Object> user = new HashMap<>();
// user.put("id", 1005);
/**
* delete():
* 第一个参数:statement id
* 第二参数: statement需要的参数
* 返回值是影响的行数
*/
int delete = openSession.delete("deleteUserById", 1006);
System.out.println(delete);
openSession.commit();
openSession.close();
}
对象类型
如果使用对象类型传递参数,对象中的属性要生成getter/setter方法,而且要保证占位符的形参在对象的属性中
/**
*
* @Description:有参数的数据传递
* @author mao
* @throws IOException
* @date 2017年10月27日
*/
@Test
public void updateUser1() throws IOException{
Reader re = Resources.getResourceAsReader("mybatis.cfg.xml");
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(re);
SqlSession openSession = build.openSession();
/**
* 第一个参数: statement id
* 第二个参数:要传递的参数对象
*
*
*/
User user = new User();
user.setPwd("jkl");
user.setId(1001);
int update = openSession.update("updateUser", user);
openSession.commit();
System.out.println(update);
openSession.close();
}
map集合类型
如果使用map集合传递参数,map集合中的key要与参数名称一致,要不找不到参数。
/**
*
* @Description:有参数的数据传递
* @author mao
* @throws IOException
* @date 2017年10月27日
*/
@Test
public void updateUser1() throws IOException{
Reader re = Resources.getResourceAsReader("mybatis.cfg.xml");
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(re);
SqlSession openSession = build.openSession();
/**
* 第一个参数: statement id
* 第二个参数:要传递的参数对象
*
*
*/
// User user = new User();
// user.setPwd("jkl");
// user.setId(1001);
Map<String, Object> user= new HashMap<>();
user.put("pwd", "zxc");
user.put("id", 1001);
int update = openSession.update("updateUser", user);
openSession.commit();
System.out.println(update);
openSession.close();
}
参数传递总结:
简单类型参数传递 只需要传递一个参数的时候,保证类型相对应
对象类型 传递的参数在对象的属性中都存在的时候
Map集合类型 当参数是多个而且与对象的属性不匹配的时候
拼接符 ${}
Select * from t_user 该sql语句,如果查询字段、表、排序无法确认,而且会随着业务的变更而改变,我们的占位符就不能满足需求,所有需要使用拼接符,但是使用拼接符容易产生注入攻击。
<!-- 使用拼接符
-->
<select id="getUsers" resultType="user" >
select ${column} from ${table} order by #{order}
</select>
<select id="getUsers1" resultType="user" >
select ${column}
</select>
<select id="getUsers2" resultType="user" >
select ${name}
</select>
对象类型
/**
*
* @Description: 拼接符 使用对象进行传值
* @author mao
* @date 2017年10月27日
*/
@Test
public void getUsers2(){
User user1 = new User();
user1.setName("name,pwd from t_user where id=100 order by name desc");
List<User> selectList = session.selectList("getUsers2", user1);
for (User user : selectList) {
System.out.println(user);
}
}
map集合类型
/**
*
* @Description:拼接符
* @author mao
* @date 2017年10月27日
*/
@Test
public void getUsers(){
Map<String, Object> map = new HashMap<>();
map.put("column", "name,pwd");
map.put("table", "t_user where id=100 ");
map.put("order", "name desc");
List<User> selectList = session.selectList("getUsers", map);
for (User user : selectList) {
System.out.println(user);
}
}
/**
*
* @Description:拼接符
* @author mao
* @date 2017年10月27日
*/
@Test
public void getUsers1(){
Map<String, Object> map = new HashMap<>();
map.put("column", "name,pwd from t_user where id=100 order by name desc");
List<User> selectList = session.selectList("getUsers1", map);
for (User user : selectList) {
System.out.println(user);
}
}
MyBitis工具类
package com.bjsxt.utils;
import java.io.IOException;
import java.io.Reader;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
/**
*
* @ClassName:MybatisUtil
* @Description:mybatis的工具类
* @Company: 北京尚学堂科技有限公司 www.bjsxt.com
* @author mao
* @date 2017年10月27日
*/
public class MybatisUtil {
private static String CONFIG_FILE = "mybatis.cfg.xml";
private static Reader re = null;
private static SqlSessionFactory sqlSessionFactory = null;
/**
* ThreadLocal:本地线程安全的
*/
private static ThreadLocal<SqlSession> th = new ThreadLocal<>();
static{
try {
re = Resources.getResourceAsReader(CONFIG_FILE);
} catch (IOException e) {
e.printStackTrace();
System.err.println("mybatis的核心配置文件读取失败!");
}
try {
//sqlSessionFactory有可能初始不了
sqlSessionFactory = new SqlSessionFactoryBuilder().build(re);
} catch (Exception e) {
e.printStackTrace();
System.err.println("mybatis的sqlSessionFactory初始化失败!");
}
}
/**
* 提供私有的构造方法,就是防止人为new对象
* User user = new User();
*/
private MybatisUtil(){
}
/**
*
* @Description:获取一次与数据库的会话
* @return
* @author mao
* @date 2017年10月27日
*/
public static SqlSession getSession(){
//当线程没有sqlsession,就通过sqlSessionFactory来获取sqlsession,并放到threadlocal里
if(th.get()==null){
th.set(sqlSessionFactory.openSession());
}
//th.get() 返回sqlsession
return th.get();
}
/**
*
* @Description:关闭session
* @author mao
* @date 2017年10月27日
*/
public static void closeSession(){
if(th.get() != null){
//关闭session
th.get().close();
//清空threadlocal中的sqlsession
th.set(null);
}
}
}
日志
asm-3.3.1.jar
cglib-2.2.2.jar --类的代理
commons-logging-1.1.1.jar --日志的工具类
javassist-3.17.1-GA.jar --
log4j-1.2.17.jar –-日志log4j的包 log for java –》log4j
log4j-api-2.0-rc1.jar–-日志log4j的包
log4j-core-2.0-rc1.jar–-日志log4j的包
mybatis-3.2.7.jar –mybatis的包
mysql-connector-java-5.1.30.jar –mysql的驱动包
ojdbc6.jar –oracle驱动包
slf4j-api-1.7.5.jar –日志的包
slf4j-log4j12-1.7.5.jar –日志的包
#根的概念,它表示日志数据的级别:info、默认使用的是info
#以什么样的形式输出:
#ServerDailyRollingFile:一天产生一个日志文件
#stdout:控制台输出
#file:日志文件
log4j.rootLogger=info, ServerDailyRollingFile, stdout
//日志输出标准,以什么资源来输出
log4j.appender.ServerDailyRollingFile=org.apache.log4j.DailyRollingFileAppender
//日志文件,以什么形式结尾或者是文件的后缀名
log4j.appender.ServerDailyRollingFile.DatePattern='.'yyyy-MM-dd
//日志文件的存放位置
log4j.appender.ServerDailyRollingFile.File=C://logs/notify-subscription.log
//日志文件的输出的布局
log4j.appender.ServerDailyRollingFile.layout=org.apache.log4j.PatternLayout
//日志文件的数据的格式
log4j.appender.ServerDailyRollingFile.layout.ConversionPattern=%d - %m%n
//后面可以继续添加内容
log4j.appender.ServerDailyRollingFile.Append=true
//=====================================================
//控制台的输出
//日志输出标准,以什么资源来输出
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
//日志文件的输出的布局
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
//日志文件的数据的格式
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %p [%c] %m%n
#namespace
#log4j.logger.com.bjsxt.mapper.UserMapper=TRACE
#bao
log4j.logger.com.bjsxt.mapper=TRACE
#lei jibie
#log4j.logger.com.bjsxt.mapper.UserMapper=TRACE
#fangfa jibie
#log4j.logger.com.bjsxt.mapper.UserMapper.getUsers=TRACE
log4j定义了8个级别的log(除去OFF和ALL,可以说分为6个级别),
优先级从高到低依次为:OFF、FATAL、ERROR、WARN、INFO、DEBUG、TRACE、 ALL。
ALL 最低等级的,用于打开所有日志记录。
TRACE designates finer-grained informational events than the DEBUG.Since:1.2.12,
很低的日志级别,一般不会使用。开发的时候使用
DEBUG 指出细粒度信息事件对调试应用程序是非常有帮助的,
主要用于开发过程中打印一些运行信息。
INFO 消息在粗粒度级别上突出强调应用程序的运行过程。
打印一些你感兴趣的或者重要的信息,这个可以用于生产环境中输出程序运行的一些重要信息,
但是不能滥用,避免打印过多的日志。
WARN 表明会出现潜在错误的情形,有些信息不是错误信息,但是也要给程序员的一些提示。
ERROR 指出虽然发生错误事件,但仍然不影响系统的继续运行。打印错误和异常信息,如果不想输出太多的日志,可以使用这个级别。
FATAL 指出每个严重的错误事件将会导致应用程序的退出。这个级别比较高了。
重大错误,这种级别你可以直接停止程序了。
OFF 最高等级的,用于关闭所有日志记录。
OFF、FATAL、ERROR、WARN、INFO、DEBUG、TRACE、 ALL。
如果将log level设置在某一个级别上,那么比此级别优先级高的log都能打印出来。
例如,如果设置优先级为WARN,那么OFF、FATAL、ERROR、WARN 4个级别的log能正常输出,
而INFO、DEBUG、TRACE、 ALL级别的log则会被忽略。
Log4j建议只使用四个级别,优先级从高到低分别是ERROR、WARN、INFO、DEBUG。
从我们实验的结果可以看出,log4j默认的优先级为ERROR或者WARN(实际上是ERROR)。
Mybatis的核心配置 文件的其他标签:
<!-- mybatis提供了一个标签来读取properties文件
-->
<properties resource="db.properties"></properties>
<!-- 开启日志
日志:记录系统运行的结果,可以以文件的形式进行保存,保存到本地磁盘中
1.导入jar包
2.在settings中添加日志开启
3.添加日志的properties文件
-->
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
<!-- 别名
将一个长路径 ,起一个别名称
typeAlias:一个对象别名,
type:指的是对象的全路径
alias:别名
package:包,它指的是,将包下面的所有对象都进行别名
别名的方式就是类的名称,不区分大小写
mybatis已经提供的了一系列的别名设置
-->
<typeAliases>
<!-- <typeAlias type="com.bjsxt.pojo.User" alias="user"/> -->
<package name="com.bjsxt.pojo"/>
</typeAliases>