文末
我将这三次阿里面试的题目全部分专题整理出来,并附带上详细的答案解析,生成了一份PDF文档
- 第一个要分享给大家的就是算法和数据结构
- 第二个就是数据库的高频知识点与性能优化
- 第三个则是并发编程(72个知识点学习)
- 最后一个是各大JAVA架构专题的面试点+解析+我的一些学习的书籍资料
还有更多的Redis、MySQL、JVM、Kafka、微服务、Spring全家桶等学习笔记这里就不一一列举出来
- 测试类中测试
//注意导包:org.apache.log4j.Logger
static Logger logger = Logger.getLogger(MyTest.class);
@Test
public void textLog4j(){
logger.info(“info:进入了selectUser方法”);
logger.debug(“debug:进入了selectUser方法”);
logger.error(“error:进入了selectUser方法”);
}
- 可以看到生成的日志文件
2.3.2、开启驼峰命名法
使用步骤:
- 在mybatis核心配置文件中设置下划线驼峰自动转换
该标签的作用是加载映射的,加载方式有如下几种(主要使用第三种):
- 使用相对类路径的资源引用xml文件,注意路径是用
/
而不是用点
- 使用映射器接口实现类的完全限定类名,引用的是接口
- 使用扫描包进行注册绑定
================================================================================
加载资源的工具类:
| 返回值 | 方法名 | 说明 |
| — | — | — |
| InputStream | getResourceAsStream(String fileName) | 通过类加载器返回指定资源的字节输入流 |
//1.加载核心配置文件
InputStream inputStream = Resources.getResourceAsStream(“mybatis-config.xml”);
// 我们也可以自己加载
InputStream inputStream = 类名.class.getClassLoader().getResourceAsStream(“mybatis-config.xml”);
SqlSessionFactoryBuilder工厂构建器:
-
SqlSessionFactory.build(InputStream inputStream)
-
通过加载mybatis的核心文件的输入流的形式构建一个SqlSessionFactory对象
String resource = “org/mybatis/example/mybatis-config.xml”;
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSessionFactory有多个方法创建SqlSession实例,常用的有如下两个:
-
SqlSessionFactory.openSession
:会默认开启一个事务,但事务不会自动提交,也就意味着需要手动提交该事务,更新操作数据才会持久化到数据库中 -
SqlSessionFactory.openSession(boolean autoCommit)
: 参数为是否自动提交,如果设置为true,那么不需要手动提交事务
| 返回值 | 方法名 | 说明 |
| — | — | — |
| SqlSession | openSession() | 通过SqlSession构建者对象,并开启手动提交事务 |
| SqlSession | openSession(boolean autoCommit) | 通过SqlSession构建者对象,如果参数为true,则开启自动提交事务 |
SqlSession 提供了在数据库执行 SQL 命令所需的所有方法 。它还提供了事务的相关操作。
成员方法如下:
-
sqlSession.commit()
:提交事务 -
sqlSession.rollback()
:回滚事务 -
sqlSession.close()
:释放资源
我们通常将mybatis获取SqlSession实例封装成一个工具类
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory;
static{
try {
// 使用Mybatis
// 第一步: 获取sqlSessionFactory对象
String resource = “mybatis-config.xml”;
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
//既然有了SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。
public static SqlSession getSqlSession(){
// SqlSession sqlSession = sqlSessionFactory.openSession();
// return sqlSession;
return sqlSessionFactory.openSession();
}
}
===============================================================================
-
分层思想:控制层(controller)、业务层(service)、持久层(dao)。
-
调用流程
-
Mapper 接口开发方法只需要程序员编写Mapper 接口(相当于Dao 接口)
-
我们之前的开发规范是编写Dao接口,之后再编写实现类DaoImpl
-
代理开发规范是编写Dao接口,之后再编写xml配置文件
Mapper 接口开发需要遵循以下规范:
-
Mapper.xml文件中的namespace与mapper接口的全限定名相同
-
Mapper接口方法名和Mapper.xml中定义的每个statement的id相同
-
Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql的parameterType的类型相同
-
Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同
4.2.1、一个参数
4.2.1.1、基本参数
我们可以使用#{}
直接来取值,写任意名字都可以获取到参数。但是一般用方法的参数名来取。
例如:
- 接口中方法定义如下
public interface UserDao {
User findUser(Integer id);
}
- xml中的内容如下
select * from user where id = #{id}
- 测试
@Test
public void findUser() throws IOException {
//定义mybatis配置文件的路径
String resource = “mybatis-config.xml”;
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//获取Sqlsession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
//获取UserDao实现类对象
UserDao userDao = sqlSession.getMapper(UserDao.class);
//调用方法测试
User user = userDao.findUser(2);
System.out.println(user);
//释放资源
sqlSession.close();
}
4.2.1.2、POJO
我们可以使用POJO中的属性名来获取对应的值。
例如:
- 接口中方法定义如下
public interface UserDao {
User findByUser(User user);
}
- xml中的内容如下
select * from user where id = #{id} and username = #{username} and age = #{age} and address = #{address}
- 测试
@Test
public void findByUser() throws IOException {
//定义mybatis配置文件的路径
String resource = “mybatis-config.xml”;
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//获取Sqlsession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
//获取UserDao实现类对象
UserDao userDao = sqlSession.getMapper(UserDao.class);
//调用方法测试
User byUser = userDao.findByUser(new User(2, “PDD”, 25, “上海”));
System.out.println(byUser);
//释放资源
sqlSession.close();
}
4.2.1.3、Map
我们可以使用map中的key来获取对应的值。
例如:
- 接口中方法定义如下
public interface UserDao {
User findByMap(Map map);
}
- xml中内容如下
select * from user where id = #{id} and username = #{username} and age = #{age} and address = #{address}
- 测试
@Test
public void findByMap() throws IOException {
//定义mybatis配置文件的路径
String resource = “mybatis-config.xml”;
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//获取Sqlsession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
//获取UserDao实现类对象
UserDao userDao = sqlSession.getMapper(UserDao.class);
//调用方法测试
Map map = new HashMap();
map.put(“id”,2);
map.put(“username”,“PDD”);
map.put(“age”,25);
map.put(“address”,“上海”);
User byMap = userDao.findByMap(map);
System.out.println(byMap);
//释放资源
sqlSession.close();
}
4.2.2、多个参数
Mybatis会把多个参数放入一个Map集合中,默认的key是argx和paramx这种格式。
例如:
-
接口中方法定义如下
-
我们一般在方法参数前使用@Param来设置参数名。
public interface UserDao {
User findByCondition(@Param(“tid”) Integer id,@Param(“username”)String username);
}
- xml中内容如下
select * from user where id = #{tid} and username = #{username}
- 测试
@Test
public void findByCondition() throws IOException {
//定义mybatis配置文件的路径
String resource = “mybatis-config.xml”;
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//获取Sqlsession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
//获取UserDao实现类对象
UserDao userDao = sqlSession.getMapper(UserDao.class);
//调用方法测试
User pdd = userDao.findByCondition(2, “PDD”);
System.out.println(pdd);
//释放资源
sqlSession.close();
}
4.2.3、总结
-
建议如果只有一个参数的时候不用做什么特殊处理。
-
如果是有多个参数的情况下一定要加上@Param来设置参数名。
4.2.4、获取参数时 #{}和${}的区别
-
如果使用#{}.他是预编译的sql可以防止SQL注入攻击
-
如果使用${}他是直接把参数值拿来进行拼接,这样会有SQL注入的危险
==========================================================================
select 语句有很多属性可以详细配置每一条SQL语句
-
id
: 就是对应的namespace中的方法名 -
resultType
: Sql语句执行的返回值【完整的类名或者别名】 -
parameterType
:传入SQL语句的参数类型
示例:
- 在UserMapper中添加对应方法
public interface UserMapper {
// 查询全部用户
List getUserList();
}
- 在UserMapper.xml中添加Select语句
select * from mybatis.user;
- 在测试类中测试
public void test(){
//第一步:获得SqlSession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
//方式一:执行SQL
UserMapper userDao = sqlSession.getMapper(UserMapper.class);
List userList = userDao.getUserList();
for (User user : userList) {
System.out.println(user);
}
// 关闭SqlSession
sqlSession.close();
}
示例2:根据id查询用户
- 在UserMapper中添加对应方法
public interface UserMapper {
// 根据ID查询用户
User getUserById(int id);
}
- 在UserMapper.xml中添加Select语句
select * from mybatis.user where id = #{id}
- 在测试类中测试
@Test
public void getUserById(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = mapper.getUserById(1);
System.out.println(user);
sqlSession.close();
}
需求:给数据库增加一个用户
- 在UserMapper接口中添加对应的方法
public interface UserMapper{
// insert
int addUser(User user);
}
- 在UserMapper.xml中添加insert语句
insert into mybatis.user(id, name, pwd) VALUES (#{id},#{name},#{pwd})
- 在测试类中测试
// 增删改需要提交事务
@Test
public void addUser(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
int res = mapper.addUser(new User(5, “哈哈2”, “1234”));
if(res > 0) {
System.out.println(“插入成功”);
}
// 提交事务
sqlSession.commit();
sqlSession.close();
}
-
在插入操作中,使用
parameterType
属性指定要插入的数据类型 -
Sql语句中使用
#{实体属性名}
方式引用实体中的属性值 -
增、删、改操作涉及数据库数据变化,所以要使用
sqlSession
对象显式的提交事务,即sqlSession.commit()
需求:修改用户的信息
- 在UserMapper接口中添加对应的方法
public interface UserMapper{
// 修改用户
int updateUser(User user);
}
- 在UserMapper.xml中添加update语句
update mybatis.user set name=#{name},pwd=#{pwd} where id = #{id};
- 在测试类中测试
@Test
public void updateUser(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
int res = mapper.updateUser(new User(4, “呵呵”, “123123”));
if(res > 0){
System.out.println(“修改成功”);
}
sqlSession.commit();
sqlSession.close();
}
需求:根据id删除一个用户
- 在UserMapper接口中添加对应的方法
public interface UserMapper{
// 删除一个用户
int deleteUser(int id);
}
- 在UserMapper.xml中添加update语句
delete from mybatis.user where id = #{id}
- 在测试类中测试
@Test
public void deleteUser(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
int res = mapper.deleteUser(4);
if(res > 0){
System.out.println(“删除成功”);
}
sqlSession.commit();
sqlSession.close();
}
假设我们的实体类,或者数据库中的表,字段或者参数过多,我们应当考虑使用Map!
5.5.1、select
- 在UserMapper中添加对应方法
public interface UserMapper{
// 万能的map
User getUserById2(Map<String,Object> map);
}
- 在UserMapper.xml中添加insert语句
select * from mybatis.user where id = #{helloid} and name = #{name};
- 在测试类中测试
@Test
public void getUserById2(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
Map<String, Object> map = new HashMap<>();
map.put(“helloId”,1);
sqlSession.close();
}
- Map传递参数,直接在sql中取出key即可!
5.5.2、insert
- 在UserMapper中添加对应方法
public interface UserMapper{
// 万能的map
int addUser2(Map<String, Object> map);
}
- 在UserMapper.xml中添加insert语句
insert into mybatis.user(id, name, pwd) VALUES (#{id},#{name},#{pwd})
- 在测试类中测试
// 传递map的key
@Test
public void addUser2(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
HashMap<String, Object> map = new HashMap<>();
map.put(“id”,5);
map.put(“name”,“啦啦啦”);
map.put(“pwd”,“123456”);
sqlSession.close();
}
- 对象传递参数,直接在sql中取对象的属性即可!
=========================================================================
在实际开发中的SQL语句没有之前的这么简单,很多时候需要根据传入的参数情况动态的生成SQL语句。Mybatis提供了动态SQL相关的标签让我们使用。
可以使用if标签进行条件判断,条件成立才会把if标签中的内容拼接进sql语句中。
例如:
select * from user
where id = #{id}
and username = #{username}
-
如果参数username为null则执行的sql为:select * from user where id = ?
-
如果参数username不为null则执行的sql为:select * from user where id = ? and username = ?
-
注意:在test属性中表示参数的时候不需要写#{},写了会出问题。
可以使用该标签动态的添加前缀或后缀,也可以使用该标签动态的消除前缀。
注意:trim标签其实在真正开发中不会太用到,主要是为了理解后面的where标签,所以这里理解即可
6.2.1、prefixOverridess属性
用来设置需要被清除的前缀,多个值可以用|分隔,注意|前后不要有空格。例如: and|or
例如:
select * from user
and
最终执行的sql为: select * from user
6.2.2、suffixOverrides属性
用来设置需要被清除的后缀,多个值可以用|分隔,注意|前后不要有空格。例如: and|or
select * from user
where 1=1 like
最终执行的sql为: select * from user 去掉了后缀like
6.2.3、prefix属性
用来设置动态添加的前缀,如果标签中有内容就会添加上设置的前缀
select * from user
1=1
最终执行的sql为:select * from user where 1=1 动态增加了前缀where
6.2.4、 suffix属性
用来设置动态添加的后缀,如果标签中有内容就会添加上设置的后缀
select * from user
where
最终执行的sql为:select * from user where 1=1 动态增加了后缀1=1
6.2.5、trim综合使用
动态添加前缀where 并且消除前缀and或者or
select * from user
id = #{id}
and username = #{username}
-
调用方法时如果传入的id和username为null则执行的SQL为:select * from user
-
调用方法时如果传入的id为null,username不为null,则执行的SQL为:select * from user where username = ?
where标签等价于:动态添加前缀where 并且消除前缀and或者or
可以使用where标签动态的拼接where并且去除前缀的and或者or。
例如:
select * from user
id = #{id}
and username = #{username}
-
如果id和username都为null,则执行的sql为:**select * from user **
-
如果id为null,username不为null,则执行的sql为:**select * from user where username = ? **
set标签等价于:动态添加前缀set 并且清除后缀逗号
可以使用set标签动态的拼接set并且去除后缀的逗号。
例如:
UPDATE USER
username = #{username},
age = #{age},
address = #{address},
写在最后
作为一名即将求职的程序员,面对一个可能跟近些年非常不同的 2019 年,你的就业机会和风口会出现在哪里?在这种新环境下,工作应该选择大厂还是小公司?已有几年工作经验的老兵,又应该如何保持和提升自身竞争力,转被动为主动?
就目前大环境来看,跳槽成功的难度比往年高很多。一个明显的感受:今年的面试,无论一面还是二面,都很考验Java程序员的技术功底。
最近我整理了一份复习用的面试题及面试高频的考点题及技术点梳理成一份“Java经典面试问题(含答案解析).pdf和一份网上搜集的“Java程序员面试笔试真题库.pdf”(实际上比预期多花了不少精力),包含分布式架构、高可扩展、高性能、高并发、Jvm性能调优、Spring,MyBatis,Nginx源码分析,Redis,ActiveMQ、Mycat、Netty、Kafka、Mysql、Zookeeper、Tomcat、Docker、Dubbo、Nginx等多个知识点高级进阶干货!
由于篇幅有限,为了方便大家观看,这里以图片的形式给大家展示部分的目录和答案截图!
Java经典面试问题(含答案解析)
阿里巴巴技术笔试心得
可以使用where标签动态的拼接where并且去除前缀的and或者or。
例如:
select * from user
id = #{id}
and username = #{username}
-
如果id和username都为null,则执行的sql为:**select * from user **
-
如果id为null,username不为null,则执行的sql为:**select * from user where username = ? **
set标签等价于:动态添加前缀set 并且清除后缀逗号
可以使用set标签动态的拼接set并且去除后缀的逗号。
例如:
UPDATE USER
username = #{username},
age = #{age},
address = #{address},
写在最后
作为一名即将求职的程序员,面对一个可能跟近些年非常不同的 2019 年,你的就业机会和风口会出现在哪里?在这种新环境下,工作应该选择大厂还是小公司?已有几年工作经验的老兵,又应该如何保持和提升自身竞争力,转被动为主动?
就目前大环境来看,跳槽成功的难度比往年高很多。一个明显的感受:今年的面试,无论一面还是二面,都很考验Java程序员的技术功底。
最近我整理了一份复习用的面试题及面试高频的考点题及技术点梳理成一份“Java经典面试问题(含答案解析).pdf和一份网上搜集的“Java程序员面试笔试真题库.pdf”(实际上比预期多花了不少精力),包含分布式架构、高可扩展、高性能、高并发、Jvm性能调优、Spring,MyBatis,Nginx源码分析,Redis,ActiveMQ、Mycat、Netty、Kafka、Mysql、Zookeeper、Tomcat、Docker、Dubbo、Nginx等多个知识点高级进阶干货!
由于篇幅有限,为了方便大家观看,这里以图片的形式给大家展示部分的目录和答案截图!
[外链图片转存中…(img-mIv9fIKe-1715644203289)]
Java经典面试问题(含答案解析)
[外链图片转存中…(img-adJXCyvV-1715644203289)]
阿里巴巴技术笔试心得
[外链图片转存中…(img-YugSw4lM-1715644203290)]