Hang tight while we fetch the video data and transcripts. This only takes a moment.
Connecting to YouTube player…
Fetching transcript data…
We’ll display the transcript, summary, and all view options as soon as everything loads.
Next steps
Loading transcript tools…
Migrating from (Spring Data) JPA to Spring Data JDBC by Jens Schauder @ Spring I/O 2024 | Spring I/O | YouTubeToText
YouTube Transcript: Migrating from (Spring Data) JPA to Spring Data JDBC by Jens Schauder @ Spring I/O 2024
Skip watching entire videos - get the full transcript, search for keywords, and copy with one click.
Share:
Video Transcript
Video Summary
Summary
Core Theme
This presentation outlines a strategic approach to migrating from Spring Data JPA to Spring Data JDBC, emphasizing the importance of Domain-Driven Design principles, particularly aggregates, and employing safe, incremental refactoring techniques.
Mind Map
Click to expand
Click to explore the full interactive mind map • Zoom, pan, and navigate
okay um welcome to my talk and uh thanks
for having me in
Barcelona um looks like a really nice
place to
visit um guess I should have brought a
little more time but anyway at least the
view outside the windows is
nice I'm going to talk about how to
migrate from Spring data jpa to Spring
data jdbc I guess that is not a surprise
for you although I do have a couple of
questions like the first question is who
actually read the
abstract okay and nobody thought it
might be worth telling someone that it's
totally bogus for those that didn't read
the abstract uh it's actually what
should have gone under my or into my
speaker bio something got mixed up there
but I guess the title kind of speaks of
itself more questions um I would like to
understand who I'm talking to who likes
jpa quite a few hands okay there's no
who of you have actually used spring
data jdbc at least in like a little toy
project a demo most of you that's good
because I try not to explain too much
about spring data jdbc
itself but who has used it in
production that are I'd say a little
more than the people that actually like
jpa so that's that's good although the a
might be
biased and who is actually migrating or considering
considering
hands honest question why no no really
like you're doing a big change to your
migrate
pdon come I get a little louder
more control more
control I I think that's in general a
valid valid reason
um but we'll see like how you think
about these reasons after the talk um to
be very clear I created spring data jdbc
I love it I consider it my third child but
but
um as with the other two Childs and
everybody that is is honest about his or
her child Childs aren't perfect
and also just
replacing someone with your own child um
easy before we start with the actual
migration we have to like settle down
some some foundations
foundations
um we are doing a talk of 50 minutes
well actually I guess I lost two minutes
um for a late start um but all this has
to be considered in the context of a
serious project like I have a little Deo
demo project that I use to to go through
this process myself um that's basically
it plus a little demo service that
actually uses this domain model and the
repositories your projects are probably
much bigger or if you have some serious
micro uh projects or microservices they
might like a single service might look
like that but then you probably have
dozens of it so whatever I show you here
or what I
discuss um yeah that looks easy for a
small project but remember in a serious
context you might have to do that dozens
maybe hundreds in some some cases
times and partly for that reason before
you start any kind of migration doesn't
matter what you migrate from or to you
don't start before you have a serious
set of
tests so test question who is
comfortable to like replace your persistence
persistence
layer and be sufficiently secure that if
there's something fatally wrong with a
persistence layer your test will tell
you hands
up okay great to see that there are many
hands up um for all others you know what
first and then there's something very
well really not very technical
walk with baby steps that's that's a
term I learned at a conference like I
don't know uh 10 years ago and the
meaning is do really really small
steps actually try doing incredibly
small uh steps because the problem is
that you easy get to in really in any
kind of development but especially with
refactorings is you think like I'm going
to solve this little problem and do a
code change and then you notice oh no
something over here is broken I'm going
to fix that oh now three things over
here are broken am I going to start to
fix those um then suddenly all my
project is readed um two weeks have
passed uh since the last time my code
compiled let alone all my tests run
that's not a good state to be in because
now you have no idea how much time you
need until you actually get back to a
stab uh state so always try to make the
smallest possible
change run all your
tests and commit and we can do that
nowadays I'm an old guy I remember stuff
like ACS CVS and srn I think um where
doing a commit was lengthy operation and
well if it worked at all nowadays we can
do that in like it's just
in the in the Shell One Step Up in the
history and return and basically a
no-brain use that
that
and even go one step further use the
Mikado method who knows the Mikado
method yeah I was afraid of that um it's
a it's a great tool I'm not going to
into much detail the basic idea is you
have a big ref factoring that you want
to achieve and you start by taking a
probably big piece of
paper and writing that goal on that
piece of paper and making a circle around
around
it then you think about like what could
the first small step be to get to that
goal and before you hit your keyboard
you write that little step on your PC of
paper make a circle around it and draw
an arrow from the first circle to the
second this arrow means to reach this
goal I have to do this other thing and
then you actually try to do the other
thing and then we are back to baby steps
does it work does it compile do all your
tests pass if
yes great you can cross out that circle
on your on your little diagram and find
the next baby step
but more likely it doesn't work
something turns red a test the compiler
complains this teaches you something it
shows you a place where you need to
change something first before you can do
the thing that you try to do so what you
do is you draw a new circle on your
piece of
paper and again connect the second
circle to the third circle with an arrow
knowing okay now I have to
do this other thing before I can do this
thing and then comes the really really
important step of the Mikado
method you undo your
changes and then from all the circles
that don't have any dependencies yet in
my little examples there's only one
Circle you try that one and maybe you
find more
circles there are two benefits to this
approach one is
you're doing baby steps like every few
minutes you're back to a stable code
base that you can commit that you can
merge with your main branch or merge the
main branch into you or rebase or
however you want to work with
that and you have a good visual
representation of what you still have to
do and if you plan like two weeks for
refactoring and after one
week you your graph hardly fix fits on
the biggest whiteboard on your office
and is still growing you know this is
not going to work in two weeks and that
is important information that you can
on so all this was pretty much technology
independent but there's one thing that
comes from Spring data jdbc itself
spring data jdbc is strongly based on
the concepts of aggregates
from domain driven design who is
familiar with the concept of Aggregates
Aggregates
okay more than the Mado method still not
enough Aggregates are again a concept
from domain driven design and an
aggregate is basically a bunch of
classes typically not very many many
Aggregates are a single class sometimes
they are two classes if you have an
aggregate that con P consists of five
classes it's probably too
big and the important thing about an
aggregate is
twofold it is always transactionally
consistent so whatever you do to an
aggregate you always do it all or
nothing and the other thing is whatever
is inside the aggregate only gets
controlled by the so-called aggregate
route which is the single class that
knows about all the others and if you
want to manipulate them uh these inner
classes you always do that through the aggregate
aggregate
route and spring data jdbc uses that in
a very important
way um the
aggregate is the unit that spring data
jdbc uses for persisting and loading
data in jpa you have all this cascading
and different fetch
strategies and if you aren't careful you
um trigger different selects when you
just access a geta or you load the whole
database into memory just when you load
one little entity um this is very
obviously obvious in Spring data
jdbc if you load an
aggregate it will load everything that
is referenced by that aggregate by
normal Java reference
refence if and the boundaries of the
Aggregates are actually defined by well
not using references anymore instead you
basically use an ID to reference a different
different
Aggregate and like understanding these
Aggregates is really important at the
end of the slides um I have a link to a
little article I wrote um you can read
up on that um that's a really important concept
and then there's one final thing you
have to think about or you probably
should think about before starting your
migration project is do you want to go
breadth first or depth first basically
the steps that I'm going to show you you
have to apply them to basically every
aggregate in your
project if you want to do a complete
migration and it's probably like if you
look at the total time you used it's
probably faster if you do the same step
for all the Aggregates that are out
there because then you're like in the
process okay I know this I have to do
this kind of stuff and then you just do
it over and over and over which might
become boring but very efficient but
then you have a lot of Aggregates like
in the middle of a
migration if there is a chance that you
don't migrate the whole project I would
recom recommend go depth first meaning
pick an aggregate completely migrated or
migrated as far as you want to and then
aggregate
so let's get
started what do you think should be the
first thing to do when migrating a
project from jpa or spring data jpa to
run your chest well yeah okay good point
I don't have that on the
slides um no but specific to the
migration what ia did I just talked about
about
Aggregates and the
problem is spring data really always is
based on Aggregates but jpa kind of
breaks that and also for many
stores it's not that important
especially jpa it's like nothing bad
happens if you ignore that at least not
in the short run so what you have to do
is actually identify your
Aggregates and for those that know how
Aggregates work in this diagram what do
yeah almost actually all the light green
boxes are
entities and the dark greens are the
repositories and in many
cases the entities and Aggregates are
actually identical but there's one case
where this isn't the case in this
shipment the the thought process here is
like can these things exist
exist
independently I can imagine a shipment
that doesn't have a
customer I can't really ship that
probably but I can do a lot of things
that I can validate it I can I can start
picking that stuff I can't just really
ship it
um but the relationship between shipment
and the items inside the shipment
that's like a shipment without any items
is kind of useless and items that don't
belong to a shipment what is even the
meaning of that so these are probably um
one one
Aggregate and um that's something I have
to to First realize for the next step
which is remove all the extra
repositories that you most likely if you
never thought about aggregates have in
your code base
base
because again I
said um an aggregate should be handled
as one unit should be persisted as
one so it doesn't make sense to have a
repository for an entity that is inside an
an
aggregate so we have a Superfluous
repository here which is the item
repository that needs to go away and
that of course it's easy in a diagram
like this um in code um that's also easy
um we just delete it if you don't notice
this has like light greenish hint which
is the in my configurations of intellig
um how it displays like this thing is
gone in this commit but of course if I
have that repository I probably used it
um so I need to change some places in my
code um
um in this case um I have this uh
service method they don't make too much
sense they are really created just to to
demonstrate the kind of issues um you
will find in your code um it accesses
directly um an item by ID and then
changes the quantity and now I have to
access that item in a different way and
again I said in the beginning about
Aggregates everything inside an
aggregate gets only accessed through the
aggregate route and I do in this little
code change the kind of a minimal
version of that I still access it from
the outside but at least I load the um
the shipment and then find inside the
shipment the correct item and then
manipulate it if I want to do the full
thing um like in the real beautiful
domain driven design uh style all this
logic should actually go into the
shipment class but that is kind of not
necessary for the migration so you can
do that whenever it fits you and it
doesn't really appear um in the
change because you now use a method in
the item um no in the shipment repos
repository that wasn't there before yet
so you have to create that method which
in this case is a simpler simple find uh
method that you can just add it might
actually mean that you have to write
custom SQL or
jpql um whatever it uh it might involve
that depends obviously heavily on your
project and I can't really do much of an
advice here
but this is a good uh place to to like
revisit the Mikado method because with a
Mikado method I would actually do this
kind of in the reverse order I would
start okay I just delete the item
repository then notice oh that doesn't
work I first have to get rid of this
invo invocation of the item method then
when I tried to do that I noticed well I
need need a new method in the sh shipment
shipment
repository again undo all my
changes implement the method for the
shipment repositories with tests
obviously then um refector this method
to use only that and no longer the item
repository and then the final step is I
can actually delete the item
repository and does that sound
complicated and kind of convoluted yes
it does but if you work work with a code
base with dozens of or hundreds of
entities that might exist already for 10
or 20 years long before you Jo uh joined the
the
me the next thing to do is make all the
safe statements
explicit jpa has this great feat feure
or I should say
feature that it POS it saves everything
in the um in the persistence
context and that can create funny
results sometimes if you're not aware of
that and it um often um uh results in
the effect that calling the safe method
of a jpa repository isn't really necessary
necessary
one example is here um in this
example I load a product and then manipulate
manipulate it
it
and then
nothing but all this runs inside a
transaction so jpa
automatically possess all this stuff
spring data jdbc will not do that for you
you
if you load an enti with spring data
jdbc it's totally disconnected from
Spring data jdbc it's just a plain class
nothing special about it not a proxy
just the class how you implemented it
and it has no way of knowing that you
actually change the data and might want
to persist that so you have to add a safe
safe
method there are other cases um
where uh this happens which is when when
you have Cascade annotations in this
example I have a shipment and I might
create a customer and then at the end I
only save the shipment but the customer
that I created here gets again due to
some um Cascade
annotations on the
shipment gets persisted as well in order
to make this work
properly when we finally switch to
Spring data jdbc we have to actually add
a save um call over there can you
actually see the colors of the diff like
color kind of I'm not able to change it
sorry lesson learned for
me once you have done
that you can actually get rid of all the
Cascade data in your repositories that
crosses Aggregates because again
Aggregates are kind of
autonomous if you have if you work on
two Aggregates at the same times domain
driven design
hardcores might actually consider that a
smell in the first place but at
least you you shouldn't cause saving one
aggregate to um have an A another
aggregate saved as well that's basically
no once you're here the next step I
would propose is
simplifying our
references in jpa it's very common to
have bidirectional references meaning
you have two classes A and B and a
references B and B references a and and
they are basically the same
relationship and spring data
jdbc can't do that which might be a
surprise if you get started with it but
the fun thing is it doesn't need
it you'll see
why so if you look at our um little
diagram again there are multiple places
where we have these bir directional
references and for each each one of
those we now need to decide like which
direction should they really
go first one customer to
shipment and like one thing that can help
help
deciding um which direction you should keep
keep
is what should come first that's the one
that gets
referenced and normally you first have a
customer before you try to ship
something to them so
the shipment should reference the
customer not the other way
around the next case is within
Aggregates there the rule is really
simple reference always go from the root
to the entities contained in the
aggregate because again we always
reference the root in the first place so
what other way would be to to reach all
the internal
stuff and in product and category
I guess one could it do both sides
like but having categories reference
products kind of feels weird to me I'm
honest I'm not able to formulate a hard
rule at this place but I think product
go and in code this can be as simple as
removing the reference but then again
you all of course have in a real world
scenario tons of places where you
reference or where you use that
reference and for those you have
basically a similar process as with a item
item
repository um you need new repository
methods for that so if somebody used to
like this this thing comes from the from
the customer if there was a code uh
place where some somebody navigated from
customer to shipment you now have to
call the shipment repository and say
customer new method and use the Mado
method same
process it gets a little more
complicated for m2n joints or m2n
relation tables
um jpa normally hides them from you
like in this
diagram there is actually an m to n
relationship um you might be able to
guess products can belong to multiple
categories and of course each category
probably has multiple products that
belong to it so in your database schema
there is this join table in between but
it doesn't appear in your entity classes
spring data
jdbc needs the needs this class
explicitly and so now you have another
aggregate that actually consists of two
classes and again in code the first part
is well you need this um reference
entity this joining entity which
basically oh you can't see my pointer
here which really just cons consists of
two references marked as ID and all The
jpa annotation to have the the right
everything and of course everywhere
where I use this I now have to use this
category once I'm at this place I have
only one: M or M to n relationships and
they are all non
bidirectional and at this this place I
now can change all these references across
across
model all the reference that cross aggregate
aggregate
boundaries that are
these kind of dissolve they are
semantically there
but they are not Java references anymore
instead of a customer I'm going to uh
ID so this
is exactly what happens in this case um
for the item that happens uh reference
the product it now references a product ID
ID
and the this might feel like a
degradation in in kind of usability of
your domain
model but really it gives you a clear
structure it defines your Aggregates now really
and and these are boundaries where your
application kind of breaks into little
pieces like a bar of chocolate and the
keyn note this morning we heard about modular
modular
modulus this is exactly one tool to to
break these apart to have to not have a
huge um modulith that has no clear
structure but well a clear structure
where you can can move pieces around and
we did all
this without using spring data jdbc in
any way
so you can do this or parts of this in
your jpa project and decide not to use
spring data
jdbc and at least in my
opinion it improves your source code the
maintainability the understandability
boundaries but of course we are here and
actually want to migrate to Spring data
jdbc so first thing
actually added to your project as a
dependency and I guess most of you are
using spring boot nowadays and that
means you just add the spring boot
starter for spring data
jdbc and um that's it it like in a
simple project it will pick up the data
source and use it and live right next to
of course if you have a more complex
setup maybe multiple data sources or fun
stuff like that of course your setup for
spring data jtbc will be more
well one thing you probably have to do
is you have to
create an idea generator one or
multiple in my little project I used
um well when I when I set up the project
I really used the simple stuff that I um
could think of while making all the
stuff that I consider not so smart um so
I have something to show you and um it
turned out um jpa used
sequences but spring data jdbc by
default expects that the
database will um create the ID and
return it when I insert
um a data set if I don't have that I
have to
explicitly generate an ID in a listener
or basically a
um a call back uh before convert call
back that has a simple method it
gets um one entity of the type that is
given up there you can use object then
you have to check what kind of entity
you have inside the method and it just
checks is this uh does this have a null
ID if that is the case it obtains in an
ID using just a jdbc template and sets
the ID if you want to use different
strategies to create
IDs feel free same same
principle and um do whatever you want
and if you do something interesting
project the next thing you probably have
to do in a real world project is write a
bunch of
converters there's like all the the
basic data types get um persisted and
loaded just fine but if you have more
complex stuff you have to write
converters I didn't present a converter
because well converter again basically
two methods one converting from your
domain type to whatever is persistable
in the database the other one converting
it back um I'm not saying that it's it's
trivial or not much work but there's
you
and once you have those that you need
for all your Aggregates you can take an
Aggregate and then actually convert it
like replace all the map
information from jpa to Spring data
jdbc and that's the one thing that you
can't really break down into smaller
steps because you
can't I guess it's obviously not have an
entity that is 50% jpa and 50% spring
data jdbc I can't even imagine how that
is would be supposed to work and um an
important thing is
um unfold your import statements because
there are quite some uh
annotations that exist in both worlds
like jpa has a table
annotation and um jpa and spring data
jdbc both have an ID
annotation and um another example is the
query annotation exists for both uh
modules but are different classes and
you have to replace one with the other
and there is still a lot of work you
probably have to create custom
cruies um uh spring data jpa is more
feature especially um regarding Cy Generation
Generation
Um but yeah there's like this is the
part where I only have a few slides
doesn't mean there's a little work for
work I don't know if that is a surprise
or if anybody came here and thought like
well they I'm sure they have like some
AI thing generating open rewrite recipes
um it's something I'm thinking about but
um didn't get beyond the thinking about
a lot of that work can be broken down
into small steps which is a good thing
and an important thing don't try to do
everything at once that won't work and
can cost you a lot of time and time is
money quite
literally most of the stuff is
untangling structures that we are kind
of they are not really caused by jpa
because I just demonstrated you can undo
them while staying well within jpa world
but jpa allows them to do that and I
think that's an
architectural Choice possibly
mistake um Fielding described
architecture as the decision like what
not to do and jpa in that sense comes
with very little architecture jpa
basically says yeah give me your model
give me your schema and one way or the
other I'm mapping one to the other
spring data jdbc is way more strict in
that regard it says I have a way to map
a model to the database and yes you of
course you can tweak things like table
and column names and stuff and you can add
add
converters but there's a very
strong I'd say ccept set that have to
fit in and it gives the application a
nice clean upright posture that is nice
to look
at so if all that is too much work for
you and you think like okay making my
application easier to understand is it
worth all that work maybe you have a a
big application with 100
entities and in the last two years
you're really only working with this
cluster of 12
entities um well you can decide to only
use spring data jtbc for new stuff you
can say okay whenever we touch something
then we are going to migrate it to
Spring data
jdbc um the two can exist in the same
project and I'm not going to say without
problem I'd say without problem from the
spring data jdbc design because
jpa has
some has some problems if you actually
use SQL against the database but again
we are separating our application first
into Aggregates and then decide okay I
going to use spring data jdbc for this
Aggregate and spring data for jpa for
this Aggregate and that should work fine
I promised a couple of
links and some I didn't promise all the
the screenshots of the code uh in this
GitHub repository there are actually two
branches like the main branch and
basically a branch further below you can
say as basically set up at this Branch
okay I have a working jpa application
and then in small steps I went up until
I have migrated everything to Spring
data jdbc
um you can play with
that then I mentioned the Mado method a
couple of times if you do any kind of
refactorings no matter if related to
Spring data jdbc or not do yourself um a
favor and get this book and read through
it I have actually never read the book
but I read it when it still was a PDF
and available for free um You probably
have to to pay a few bucks but you're
software developers I think you can you
will be able to pay for
that and um for those that are really
new to Spring data jdbc there's an
article where I try to explain this
Aggregates and reference stuff um that's
probably helpful in
understanding why we did all these
things that I just explained
explained
and with that I'm done and open for
questions if you want [Applause]
Click on any text or timestamp to jump to that moment in the video
Share:
Most transcripts ready in under 5 seconds
One-Click Copy125+ LanguagesSearch ContentJump to Timestamps
Paste YouTube URL
Enter any YouTube video link to get the full transcript
Transcript Extraction Form
Most transcripts ready in under 5 seconds
Get Our Chrome Extension
Get transcripts instantly without leaving YouTube. Install our Chrome extension for one-click access to any video's transcript directly on the watch page.